[Ethereum] How to securely generate a random number in the smart contract


If I am writing a smart contract for some kind of (gambling) game, how can I generate a random number securely? What are the best practises and security trade-offs to be aware of?

Best Answer

There are a few trade-offs and key points to keep in mind in this area.

  1. Any decision that a user makes which affects the outcome gives that user an unfair advantage. Examples include:

    • Using a blockhash, timestamp, or other miner-defined value. Keep in mind that the miner has a choice of whether to publish a block or not, so they could conceivably have one chance at the prize per block they mine.
    • Any user-submitted random number. Even if the user pre-commits to a number, they have a choice in whether or not to reveal the number.
  2. Everything that the contract sees, the public sees.

    • This means that the number should not be generated until after entry into the lottery has been closed.
  3. The EVM will not outrace a physical computer.

    • Any number that the contract generates may be known before the end of that block. Leave time between the generation of the number and its use.

Now for the technique:

Perfectly Decentralized Lottery-Style Non-Malleable Commitment:

  1. The Casino sets aside a reward for a random number
  2. Each user generates their own secret random number N
  3. Users create their commitment by hashing their N with their address: bytes32 hash = sha3(N,msg.sender)1
    • note: steps 2 & 3 should be performed locally, in secret
  4. Users send their hash to the contract, along with ether greater than or equal in value to the value of the random number.2
  5. Submissions continue for some number of blocks, or until sufficient participants have joined.

Once the submission round has ended, the reveal round begins.

  1. Each user submits their random number N to the contract
  2. The contract verifies that the sha3(N,msg.sender) matches the original submission

If the user does not submit a valid N in time, his deposit is forfeit.

  1. The Ns are all XOR'd together to generate the resulting random number.
  2. This number is used to determine which of the participants receives the reward. (N % numUsers)3

Notes and alternatives:

1. The users must concatenate their address to their N before hashing. Otherwise, another user could simply submit an identical hash, then wait for N to be revealed, then submit that. N XOR N equals 0, so this could be used to cancel out all submissions except the attacker's.

2. This is where the trade-offs come in. The last person to reveal their N has a choice whether to reveal or to not reveal. This essentially gives them a double chance at winning. Enter enough times, and you get a new choice for each entry. Hint: Miners chose the order of transactions in a block. In order to discourage this, users must put up a large security deposit, equal to the value they would gain by manipulating the random number. This could be a problem for many users, especially for large jackpots, even with game-theoretic optimizations.

  • A commonly used alternative is a semi-centralized system. This requires the "house" to submit the first hash and last reveal. If the house does not fulfill their duty, everyone's ether is returned. This has issues, such as the house choosing to flake if a jackpot payout is imminent. The idea is that the house's reputation is at stake.
  • Note that this essentially centralizes the whole system. One simply needs to take down the house for the whole operation to be shut down. This risk can be reduced by hiring multiple trusted non-players to be the first/last commiters.
  • Another trick is to use hired professional third parties to "mine" randomness for you, so that the players need not be bothered with the process.

3. A reward is necessary in order to foster competition among participants. It causes a classic tragedy-of-the-commons/prisoner's dilemma situation. Collusion between participants would allow them to win a large pot and split it among themselves, but if everyone knows what everyone else will submit, they know what they themselves should submit to win the reward. Thus, if the reward is larger than the value of the random number divided by the number of players, then everyone is incentivised to keep their own number a secret in order to have a better shot at the reward. Note that only one of the participants needs to submit a good random number, and the result will be unpredictable.

Examples: Chainlink VRF, RANDAO, The thread where I first thought through this

Related Topic