Commit Reveal Scheme on Ethereum

Hiding Actions and Generating Random Numbers

Austin Thomas Griffith
Gitcoin
8 min readDec 14, 2018

--

The Ethereum blockchain is public.

Since all transactions are public we have to use extra tricks to keep some things temporarily hidden. Let’s say we need input like an answer to a quiz or a move in a game from a group of players. We don’t want these players to be able to just watch the blockchain for their competitors’ answers. What we’ll do is have everyone hash their answer and submit that first (the commit). Next, everyone will submit their real answer (the reveal) and we can prove on-chain that it hashes to the committed value.

The Ethereum blockchain is public and deterministic.

That means random number generation is a hard problem. Miners can’t just generate randomness right now. One trick many have used in the past is to use the previous blockhash as a source or randomness. This has a few flaws including its public nature and susceptibility to miner tampering.

What we’ll do is have a player generate a random number and then hash it and send it on-chain (the commit). Next, on a future block, we’ll have them submit their original random number. Finally, we’ll hash their random number (that the miner shouldn’t know about) with the blockhash on the commit block (that the player couldn’t know about). This final hash is a pretty good source of randomness on-chain because it gives the player an assurance that the the miner didn’t manipulate it.

However, we probably shouldn’t use this randomness for something that is worth more than the block reward. Players and miners could collude and by sharing information they would have the opportunity to withhold mined blocks that aren’t winners for them.

This isn’t really a worry if we are just trying to generate a good random number for a game. We just want players to be confident that if they don’t share their reveal, they will get a good random number that isn’t manipulated by the miners. Let’s build out an example project to show how this works.

We will start with an empty Clevis project:

If you are unfamiliar with Clevis there are numerous articles and tutorials.

Let’s create our contract:

We will have a commit function that takes in one bytes32 and stores it:

Before we can deploy, we’ll want to have ganache running:

Let’s go ahead and compile it and test it from the command line:

Then let’s make our first commit, sixteen cows:

Then let’s check that everything is stored correctly:

Note: you can get your 0th address by running ‘clevis accounts’

We can also follow the events to make sure they are triggered correctly:

Neat. Now it’s time for the reveal.

Let’s start with our predictable hash function that can be used off-chain too:

Then let’s write our arduous reveal function and make sure we check everything we can think of:

The current version of the full contract is located here.

I added in a max for the random number too:

We could test this more from the command line, but thanks to Dapparatus, it’s easy to dive right into a frontend POC. This allows me to get a feel for how the contract works without poking at the CLI.

Let’s take a look at our src/app.js file. We’ll want to uncomment a few things and change a few pieces of scaffolding to point to our contract:

Okay let’s fire up our app:

Okay, I broke things on purpose, you will probably see:

To fix this, you need to make sure your contracts are ‘published’:

Nice, now our frontend is looking right:

As with all Clevis & Dapparatus builds, don’t forget to add your MetaMask account to the tests/clevis.js file so you will have some test ETH:

Note: you will need to run ‘clevis test full’ for this change to take effect

Onward! Okay, hitting the commit button doesn’t do anything. Let’s wire that up so it talks to our smart contract:

Now we can commit and the event fires! Cool. Let’s build a reveal button:

And there we go, we can see that a random number is being generated on-chain. Let’s add one more nice to have feature and display the random number:

Rad, now we can see that we are generating random numbers on-chain:

As I mentioned before, the game theory here only holds up if the reward of generating the number is less than the block reward. A miner can collude with a player and then withhold a specific mined block to hope for a better result. But, this method gives the player confidence that the random is tamper proof from the miners if kept secret.

What else can we use the commit reveal scheme for?

Let’s say you have an application where a group of users all send in some kind of input but you don’t want them to know each others’ answers until they answer too.

We’ll keep our original commit function in our smart contract, that will work exactly the same. Then, we’ll add revealAnswer function that will take in two bytes32, one for a player’s answer and one for a player’s salt.

Note: the salt is used to obfuscate the answer hash. Competitors could guess players’ answers and try to reverse the hash without a salt.

We will also create a getSaltedHash function to use both in our contract and in our frontend:

We can make sure this compiles, deploys, and publishes correctly with:

Now let’s focus on the frontend. Let’s say we are building a quiz app and we’ll pose our first question with an input box:

Next, any time someone enters a value in our input box we will want to salt and hash it:

Then, let’s display all of this information in the frontend for clarity.

Let’s also add in buttons for the commit and reveal:

Finally, we’ll want to track the answer events:

And display them in a nice way with the identicon of the player:

You can view the full frontend code here.

Now multiple players can commit their answers and eventually reveal them:

Neato, gang.

Conclusion

Using a commit reveal scheme is a powerful way to embrace the unidirectional properties of a hash function. You can make an attestation on-chain while keeping the information private until you want to reveal it. You can also use this method to assure players that their random numbers aren’t being tampered with by miners.

Thanks for following along! The code repo is located here. Check out all my publications and projects at https://austingriffith.com or hit me up on Twitter as @austingriffith!

--

--

Responses (3)