FHEVM Dice Game DApp π²
Brief and Full summary
A privacy-preserving dice guessing game built with Zama's FHEVM (Fully Homomorphic Encryption Virtual Machine) technology. Players can make encrypted guesses and roll dice with complete privacy - only they can decrypt their own results.
CDN Based Project Structure
- GitHub Repository to this project
- Note this project structure is for CDN integration.
fhevm-dice-dapp-cdn/
βββ contracts/ # Smart contracts
βββ frontend/ # React application
βββ tasks/ # Hardhat tasks
βββ test/ # Contract tests
βββ deploy/ # Deployment scripts
βββ hardhat.config.ts
βββ package.json
βββ README.md
SDK Based Project Structure
- GitHub Repository to this project
- Note this project structure is for SDK integration.
hello-fhevm-dice-sdk/
βββ LICENSE
βββ README.md
βββ package.json
βββ package-lock.json
βββ tsconfig.json
βββ scripts/
β
βββ packages/
βββ fhevm-hardhat-template/ # Smart contracts & deployment
βββ fhevm-react/ # FHE encryption utilities
βββ postdeploy/ # Post-deployment scripts
βββ site/ # React Frontend application
Game Overview
The FHEVM Dice Game is a privacy-first gambling DApp where:
- Players pick a number (1-6) or let the system choose randomly
- Entropy is generated through mouse movement for true randomness
- Encryption happens client-side using FHEVM SDK
- Computation occurs on-chain with encrypted values
- Results remain private until players decrypt them
Privacy Features
- Encrypted Guesses: Your guess is encrypted before submission
- Encrypted Dice Rolls: Generated on-chain using encrypted seeds
- Private Results: Only you can decrypt your game outcomes
- Verifiable Fairness: Cryptographic proofs ensure game integrity
Architecture Overview
Complete Encryption & Computation Flow
1. Entropy Collection & Seed Generation
// Mouse entropy collection in PlayDice.js
const startEntropyCapture = () => {
const onMove = (e) => {
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
entropyRef.current.push(`${x},${y},${e.timeStamp}`);
};
// Collect for 2 seconds
setTimeout(() => {
const data = entropyRef.current.join('|');
const hash = hash32(data); // FNV-1a hash
const seedNum = hash % 1000000007; // Prime modulo
setSeed(String(seedNum));
}, 2000);
};
2. Client-Side Encryption Process
Code Implementation:
// Encryption in useDiceGame.js hook
const playDice = async (seedNumber, guessNumber) => {
// Initialize FHEVM SDK
await window.relayerSDK.initSDK();
const config = { ...window.relayerSDK.SepoliaConfig, network: window.ethereum };
const fhevm = await window.relayerSDK.createInstance(config);
// Encrypt seed
const seedInput = await fhevm.createEncryptedInput(contractAddress, account);
await seedInput.add32(seedNumber);
const seedEnc = await seedInput.encrypt();
// Encrypt guess
const guessInput = await fhevm.createEncryptedInput(contractAddress, account);
await guessInput.add32(guessNumber);
const guessEnc = await guessInput.encrypt();
// Submit to contract
const tx = await contract.playDice(
seedEnc.handles[0], seedEnc.inputProof,
guessEnc.handles[0], guessEnc.inputProof,
{ value: entryFee }
);
};
3. On-Chain FHE Computation
function playDice(
externalEuint32 inputSeed,
bytes calldata seedProof,
externalEuint32 inputGuess,
bytes calldata guessProof
) external payable {
// Convert external encrypted inputs
euint32 encryptedSeed = FHE.fromExternal(inputSeed, seedProof);
euint32 encryptedGuess = FHE.fromExternal(inputGuess, guessProof);
// Store encrypted values
_playerGuess = encryptedGuess;
_lastDiceRoll = _generateDiceRoll(encryptedSeed);
// FHE computation: Check if player won
_isWinner = FHE.eq(_lastDiceRoll, _playerGuess);
// Grant decryption permissions
FHE.allow(_lastDiceRoll, msg.sender);
FHE.allow(_playerGuess, msg.sender);
FHE.allow(_isWinner, msg.sender);
}
4. Verifiable Fair Dice Generation
The dice generation uses a deterministic but unpredictable algorithm:
function _generateDiceRoll(euint32 seed) internal returns (euint32) {
euint32 salt = FHE.asEuint32(42); // Fixed salt
euint32 combined = FHE.add(seed, salt); // Combine with seed
euint32 mask = FHE.asEuint32(7); // Mask for modulo
euint32 masked = FHE.and(combined, mask); // Apply mask
euint32 one = FHE.asEuint32(1); // Add 1 (shift 0-7 to 1-8)
euint32 result = FHE.add(masked, one); // Get 1-8 range
euint32 six = FHE.asEuint32(6); // Cap at 6
return FHE.min(result, six); // Return 1-6
}
- Deterministic: Same seed always produces same result
- Unpredictable: Player provides seed via mouse entropy
- Transparent: Algorithm is public on blockchain
- Cryptographically Secure: FHE operations prevent manipulation
5. Decryption & Result Verification
const userDecryptValue = async (ciphertextHandle, valueType) => {
// Initialize FHEVM instance
const instance = await window.relayerSDK.createInstance(config);
// Generate keypair for decryption
const keypair = instance.generateKeypair();
// Create EIP-712 signature for authorization
const eip712 = instance.createEIP712(keypair.publicKey, ...);
const signature = await signer.signTypedData(eip712.domain, eip712.types, eip712.message);
// Perform decryption
const result = await instance.userDecrypt(
[{ handle: ciphertextHandle, contractAddress }],
keypair.privateKey,
keypair.publicKey,
signature,
...
);
return valueType === 'bool' ? Boolean(result[ciphertextHandle]) : Number(result[ciphertextHandle]);
};
Security & Privacy Features
1. Input Privacy
- Player guesses are encrypted client-side
- Seeds are generated from unpredictable mouse movement
- No plaintext values are transmitted
2. Computation Privacy
- All operations happen on encrypted data
- Contract never sees plaintext values
- Results are computed homomorphically
3. Access Control
// Only the player can decrypt their own results
FHE.allow(_lastDiceRoll, msg.sender);
FHE.allow(_playerGuess, msg.sender);
FHE.allow(_isWinner, msg.sender);
4. Fairness Verification
// Frontend tracks fairness proof
setFairness({
seed: seedNumber,
guess: guessNumber,
commitment: sha256(seed),
txHash: tx.hash
});
Technical Implementation
Frontend Architecture
Key Components:- PlayDice.js: Handles user interaction, entropy collection, and game submission
- DiceResults.js: Manages encrypted result display and decryption
- useDiceGame.js: Custom hook managing contract interactions and FHEVM SDK
- useWallet.js: Wallet connection and network management
// Game state in useDiceGame hook
const [encryptedState, setEncryptedState] = useState({
lastDiceRoll: '0x',
playerGuess: '0x',
winnerStatus: '0x'
});
const [decryptedState, setDecryptedState] = useState({
lastDiceRoll: null,
playerGuess: null,
winnerStatus: null
});
Smart Contract Architecture
Core State Variables:euint32 private _lastDiceRoll; // Encrypted dice result
euint32 private _playerGuess; // Encrypted player guess
ebool private _isWinner; // Encrypted win status
- Play: Submit encrypted inputs with entry fee
- Compute: Generate dice roll and check winner (all encrypted)
- Store: Save encrypted results with player access permissions
- Decrypt: Player can decrypt their own results off-chain
Prerequisites & Setup
Requirements:
- Node.js 18+ (LTS version)
- MetaMask wallet
- Sepolia testnet ETH
Quick Start:
# 1. Clone and setup
git clone https://github.com/chimmykk/fhevm-dice-dapp
cd fhevm-dice-dapp
npm install
# 2. Configure environment
cp .env.example .env
# Add your MNEMONIC and INFURA_API_KEY
# 3. Build and test
npx hardhat compile
npx hardhat test
# 4. Deploy (choose one)
# Local development:
npx hardhat node # Terminal 1
npx hardhat deploy --network localhost # Terminal 2
# Or deploy to Sepolia:
npx hardhat deploy --network sepolia
# 5. Start frontend
cd frontend
npm install
npm start
How to Play
- Connect Wallet: Connect MetaMask to Sepolia testnet
- Generate Entropy: Hover mouse over dice area for 2 seconds
- Make Guess: Click a dice face (1-6) or let system choose randomly
- Roll Dice: Click "Roll Dice" to submit encrypted guess
- Decrypt Results: Click "Decrypt All" to reveal your outcome
Testing & Verification
Automated Testing:
npx hardhat test
Manual Testing:
# Play via CLI (choose your network)
# For Sepolia testnet:
npx hardhat --network sepolia task:play-dice --guess 4 --seed 12345
# For local hardhat node:
npx hardhat --network localhost task:play-dice --guess 4 --seed 12345
# View results
# Use the frontend to decrypt and verify results
Frontend Testing:
- Test wallet connection
- Verify entropy collection
- Check encryption/decryption flow
- Validate game fairness
π² FHEVM Dice Game Mastery
Test your understanding of the complete FHEVM dice game implementation!
Question 1 of 6Randomness & Entropy
How is randomness generated in the FHEVM dice game?
Live Demo
-
Deployed Contract (Sepolia):
- CDN Version:
0xA6915c97f44f1708e37dD871CCE991fD6D45E943
- SDK Version:
0x31630746e870D3D57e8B708ac479f269e1Da4c10
- CDN Version:
-
Frontend Demos:
Learn More
- Zama Documentation: Complete FHEVM guide
- FHEVM Hardhat Plugin: Development tools
- FHE Solidity Library: Smart contract development
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
Built with β€οΈ using Zama FHEVM - Where Privacy Meets Smart Contracts