A generic commit-reveal scheme contract for fair randomness and sealed submissions on Ethereum.
Built with Foundry.
- Two-phase commit-reveal: Prevents frontrunning and ensures fairness
- Round-based: Multiple independent rounds with configurable durations
- Combined randomness: XORs all revealed values for unpredictable outcomes
- Utility functions: Built-in random number generation from combined entropy
- Fair lotteries/raffles - Everyone commits a number, reveals determine winner
- Sealed-bid auctions - Bids hidden until reveal phase
- Rock-paper-scissors - Commit choice, reveal simultaneously
- Multi-party randomness - Combine entropy from multiple participants
- Voting schemes - Private votes until counting begins
The commit-reveal pattern prevents manipulation:
- COMMIT PHASE: User submits
hash = keccak256(abi.encodePacked(value, salt)) - REVEAL PHASE: User submits
(value, salt), contract verifies hash matches
Since the hash is one-way, no one can see your value during commit phase. And once committed, you can't change it.
Timeline:
├─────────────────┼─────────────────┼─────────────────>
│ COMMIT PHASE │ REVEAL PHASE │ FINALIZED
│ Submit hashes │ Reveal values │ Use results
CommitReveal cr = new CommitReveal();
// Create a round with 1 hour commit and 1 hour reveal
uint256 roundId = cr.createRound(1 hours, 1 hours);// Off-chain: pick your value and a random salt
bytes32 value = keccak256("my_secret_number");
bytes32 salt = bytes32(uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp))));
// Compute commitment hash (can use helper or compute locally)
bytes32 commitHash = cr.computeCommitmentHash(value, salt);
// Submit commitment
cr.commit(roundId, commitHash);// After commit phase ends, reveal your original values
cr.reveal(roundId, value, salt);// After reveal phase, finalize the round
cr.finalizeRound(roundId);
// Get combined randomness (XOR of all revealed values)
(,,,,bytes32 combinedRandomness,) = cr.getRound(roundId);
// Or use the utility function for bounded random number
uint256 winnerIndex = cr.getRandomNumber(roundId, numberOfParticipants);// 1. Create lottery round
uint256 roundId = lottery.createRound(1 hours, 1 hours);
// 2. Players commit (during commit phase)
bytes32 myValue = keccak256(abi.encodePacked(msg.sender, block.timestamp));
bytes32 mySalt = keccak256("secret");
lottery.commit(roundId, lottery.computeCommitmentHash(myValue, mySalt));
// 3. Players reveal (during reveal phase)
lottery.reveal(roundId, myValue, mySalt);
// 4. Pick winner (after reveal phase)
lottery.finalizeRound(roundId);
address[] memory players = lottery.getParticipants(roundId);
uint256 winnerIdx = lottery.getRandomNumber(roundId, players.length);
address winner = players[winnerIdx];| Function | Description |
|---|---|
createRound(commitDuration, revealDuration) |
Create a new commit-reveal round |
commit(roundId, commitmentHash) |
Submit your commitment hash |
reveal(roundId, value, salt) |
Reveal your committed value |
finalizeRound(roundId) |
Mark round as complete |
| Function | Description |
|---|---|
computeCommitmentHash(value, salt) |
Helper to compute commitment hash |
getRound(roundId) |
Get round details |
getPhase(roundId) |
Get current phase (0=commit, 1=reveal, 2=finished) |
hasCommitted(roundId, address) |
Check if address committed |
hasRevealed(roundId, address) |
Check if address revealed |
getRevealedValue(roundId, address) |
Get revealed value for address |
getParticipants(roundId) |
Get all participants |
getRandomNumber(roundId, maxValue) |
Get bounded random number |
forge buildforge testforge test -vvvforge test --gas-report- Salt entropy: Use high-entropy salts (randomness + unique data)
- Timing: Commit before deadline; don't reveal early
- Last revealer advantage: In some games, last revealer could choose not to reveal if they'd lose. Consider penalties or deposits.
- Collusion: Multiple parties could share values before reveal. Design around this if needed.
Deploy to Base:
forge create src/CommitReveal.sol:CommitReveal \
--rpc-url https://mainnet.base.org \
--private-key $PRIVATE_KEYMIT
Built by Dragon Bot Z 🐉