31

Several people are playing a game with random events and require a way to produce a random number. (Such as dice rolls or a lottery.)

Can this be done such that each player has the power to be reasonably sure that the random number was fairly selected, without having to trust anyone else?

This question stems from a discussion in comments to my answer on the Bitcoin SE. I came up with a protocol but someone else spotted a flaw. This site seems more appropriate.
Please feel free to make use of my answer to that question.

billpg
  • 711
  • 5
  • 16

4 Answers4

21

The answer you posted is actually correct (more or less, see below): have each participant commit to their random number $r_i$ by publishing, e.g., $\mathcal{H}(r_i)$ in the first round. And then in the second round, each participant opens the commitment by publishing $r_i$ and everyone checks that it matches the committed value by hashing it. The final random number is the XOR of each $r_i$.

The commenter there suggested an attack if there is a collision. However the definition of a secure hash function is that its collision-resistant. For a good modern hash function like SHA256, that is the case.

There are two subtleties.

The first is that your scheme only works for large random number, large enough that an attacker couldn't try every possible value for $r_i$, hash it, and see if it matches. For committing to small values, you need a randomized commitment function. Good randomized commitments are based on discrete logarithms but you could construct one (with reasonable safeness) using a hash function by generating a large random value $a_i$ and then computing your commitment as $\mathcal{H}(r_i||a_i)$. To open, reveal both $r_i$ and $a_i$. To change $r_i$, you'd have to find a different $a_i$ so that the hash is the same: this is hard based on collision resistance. The bitlength of both $r_i$ and $a_i$ must be predetermined so it is clear from $r_i||a_i$ where to split the value into $r_i$ and $a_i$ (otherwise you could open it to different values by simply splitting in a different spot).

The second subtlety is that the last participant to reveal his value will learn the accumulated random number before he reveals his number (he can see everyone else's number and he knows his own). This may cause him to abort if he doesn't like the result. You can do more complicated things to provide fairness, but generally if any participant refuses to open their commitment, the protocol should be restarted from the beginning with that participant excluded.

Also read this answer from @D.W. on a different question where (s)he explains the same protocol.

PulpSpy
  • 8,767
  • 2
  • 31
  • 46
9

The problem pointed out by JGWeissman on Bitcoin.SE is only an issue if the hash function lacks collision resistance. Admittedly, collision resistance is one of the strongest properties usually demanded of hash functions, and collision attacks have been found for some hash functions commonly used in the past, such as MD5, but still, any secure cryptographic hash function should be collision resistant.

In fact, a simpler scheme should work:

  1. Each player $i$ chooses a random number $x_i \in \{0,\dotsc,n-1\}$ and a random $k$-bit string $s_i$, for some reasonably large $k$ (say, $k=128$).
  2. Each player announces $h_i = H(i \,||\, s_i \,||\, x_i)$, where $H$ is a collision-resistant hash function and $||$ denotes concatenation.
  3. After all players have announced their $h_i$, they now reveal their $s_i$ and $x_i$. Each player checks that the $h_j$ value announced by every other player $j$ in step 2 matches that player's $s_j$ and $x_j$.
  4. The final random number $x$ is calculated as the sum of all the $x_i$ values modulo $n$.

The value $h_i$ announced in step 2 is called a commitment. By publishing $h_i$, player $i$ commits to a specific $x_i$ without actually revealing $x_i$ itself. In this way, each player $i$ can be sure that the other players chose their random numbers without knowing $x_i$.

The purpose of the salt $s_i$ is simply to prevent brute force cracking of $h_i$ by trying each possible value of $x_i$ in turn. The player identifier $i$ is included in the hash to prevent a cheating player from copying another player's commitment. I assume that the identifiers are unique and known to all players in advance, or at least before step 3. (Another way to prevent such replay attacks would be to abort the protocol in step 3 if any two commitments are identical, which, due to the inclusion of the salt, should virtually never occur by chance.)

Actually, if the length of $h_i$ is substantially greater than $k\;\log_2(n^2 - n)$, this protocol may be secure even if $H$ is not collision-resistant, simply because there may be no exploitable collisions to be found. In particular, assuming that the outputs of $H$ are uniformly distributed over the set of $m$-bit strings, with $2^m \gg 2^k$ (and $2^m \gg n^2$), the probability of there being at least one exploitable collision is approximately

$$1-\left(1-\frac{1}{2^m}\right)^{2^k\tfrac{n^2-n}{2}} \approx 1-\exp \left(-2^{k-m}\frac{n^2-n}{2}\right) \approx 2^{k-m}\frac{n^2-n}{2}.$$

However, keep in mind that you also don't want to make $k$ too small, since then the salt becomes ineffective. Increasing $m$ should always be safe, though.

Ilmari Karonen
  • 46,700
  • 5
  • 112
  • 189
6

Say $m$ persons meet physically and want to draw a positive integer $x$ less than $n$.

Each person $j$ secretly selects a positive integer $x_j$ less than $n$, writes it down on a piece of paper, and fold it to hide her choice. The $m$ folded pieces of paper are brought together then publicly unfolded, revealing the $x_j$. The outcome of the protocol is $x = (\sum x_j)\mod n$. To illustrate with $n=10$, the $m$ digits $x_j$ are added and the rightmost digit of the sum is $x$.

If any of the person participating has chosen her $x_j$ at random, then $x$ is random. Hence, no participant can complain that $x$ is not random.

It is possible to replace the pieces of papers with electronic exchanges of messages: in addition of $x_j$, each person draws a random $r_j$, and sends $H_j = Hash(x_j \| r_j)$ to all the others, which constitutes her commitment on the choice of $x_j$. When everyone has all the commitments, everyone reveals her $x_j$ and $r_j$. The outcome is computed as above, and the $H_j$ can be verified by anyone from $x_j$ and $r_j$. If the exchange of messages is reliable, no one can complain.

fgrieu
  • 149,326
  • 13
  • 324
  • 622
1

Two variations.

If one of the "players" is going to generate the number for others to guess (lottery) then you could do it this way:

  1. Collect a token from each participant (a nonce, a random number, a favorite color, etc.)
  2. Generate or select the secret number.
  3. Hash the generated number with the tokens.
  4. Publish the hash and the tokens.
  5. Allow each other player to guess. After the guesses are complete and published you publish the secret number.
  6. Everyone can verify it is the actual number by repeating the hash.

If you have multiple "players" who are each equal in the guessing then do it this way:

  1. Collect a token from each players (a nonce, a random number, a favorite color, etc.)
  2. Publish the tokens to all players.
  3. Hash the tokens.
  4. Use the hash to see a PRNG or RNG to generate the random numbers.
  5. Everyone can repeat the process to generate the same random numbers. Of course as soon as you publish the tokens then all future random numbers are known.
Jim McKeeth
  • 931
  • 1
  • 8
  • 16