1

I am making a 2 player dice game that runs for n rounds. To create random dice roles im using a concept a understood from randao.

each user generates n sha3 hashes recursively of a random seed : e.g. H[0] = sha3(sha3(seed)) H[1] = sha3(sha3(H[0])) ... H[n] = sha3(sha3(H[n-1]))

During the nth round, we xor the H[nth] value of each user to be used as a random value for that round:random_result

My Question: What is the best strategy to map the 256 bit random_result to a 6 sided dice without completely botching the entropy?

user462003
  • 53
  • 4

2 Answers2

4

Method 1 - Big Integer Math

Convert the 256 bit random_result to an unsigned big-integer. Divide by 6 and take the remainder. Your die roll result is the remainder plus one.

$6$ does not evenly divide $2^{256}$. It divides about $1.93\times10^{74}$ times with an exact remainder of $4$. That means values $1$-$4$ are over represented but by a negligible amount, since they're only represented once more than $5$ and $6$ over a gigantic range.

The bias towards low die rolls is much much much much less than $2^{-128}$, modern cryptography's slightly arbitrary threshold for the maximum detectable amount of bias in probability.

Method 2 - "Small" Integer Math

Let $M = 6 \times floor(2^{32} \div 6) = 4294967292$, ie. the largest multiple of 6 that fits into a 32-bit unsigned integer.

Split the 256 bits into 8 32-bit unsigned numbers. Find the first value one of those values less than $M$ and return one plus the remainder of its value divided by 6. This returns value has a value a range of values $[1, 6]$.

The reason for using values in the range $[0,M-1]$ instead of $[0, 2^{32}-1]$ is because the latter is not evenly divided by 6. Random numbers in the former range lead to a perfectly uniform distribution.

The probability of one 32-bit value being rejected is $p = (2^{32} - M) \div 2^{32} \approx 9.32 \times 10^{-10}$. All 8 are rejected with $p^8 \approx 5.66 \times 10^{-73}$ probability which is very unlikely. The exact probabilities happen to be $p = 2^{-30}$ and $p^{8} = 2^{240}$. Again, this is less than $2^{-128}$, so you shouldn't expect it to happen.

If it does fail 8 times you can derive more 256 bit numbers by hashing random_result concatenated with a counter. Or you can just use the final 32 bit value if the first 7 fail. The probability of that happening is small and the resulting bias is smaller.

The reason why I specify 32 bit numbers is for ease of implementation and for optimization reasons. There isn't any cryptographic relevance. 64-bit numbers and 64-bit division works as well, but it might not be available in some scripting languages and 32-bit division may be faster than 64 bit division on 32-bit and 64-bit architectures.

You could use 3 bit chunks. Then you could eliminate division entirely because 6 only divides 8 once. Rejecting an individual chunk happens with $1/4$ chance. Rejecting 85 times is less than $6.7 \times 10^{-52}$ or $2^{-170}$.

Method 3 - Seed a PRNG

This would be a really easy if CS-PRNGs were implemented in standard language libraries or popular add-on libraries with a similar API to those for non-secure PRNGs. Using standard PRNGs doesn't work for every application either because of statistical artifacts, small state space, predictability, or lack of a good seeding algorithm.

Edit: Avoid this method. I don't have a single example I can cite. There are too many ways it could go wrong.

 

No method has significant bias and therefore the entropy of the die roll has very close to $\log_2 6$ bits of entropy. (Assuming reasonably high entropy seed, like 128 bits of entropy. It doesn't need to have 256 bits of entropy.)

I don't think you want an answer based on entropy. I don't know what you mean by "botching the entropy" and I assume you don't know either.

For each method you can estimate entropy of the result by treating the entropy of the hash output about equal to $min(256, \text{seed-entropy})$ and calculating the probability of each outcome 1 through 6 by computing how many hash outputs map to that die-roll-value.

Since we already know the bias to be incredibly small we know that the die-roll result is about uniform. Since it is about uniform we know it has about the maximum entropy you can get out of 6 element discrete uniform distribution, $\log_2 6$.

Future Security
  • 3,381
  • 1
  • 10
  • 26
-2

This post has nothing to do with cryptography. Using of SHA does not automatically mean the question is related to cryptography. If one is developing a game that uses random generator based on a Geiger counter and an A-bomb, this doesn't mean the post is related to WMD or physics.

The most important thing in the OP is that each player gets equal chances. This has nothing to do with how (cryptographically) good the number generator is, how good the numbers are distributed, etc. Here is why.

A) Two players use the same device (smartphone, tablet, laptop, PC). The both have equal chances to win, no matter how good the number generator is. This is obvious. If not, I'll answer your questions below.

B) Two players use different devices (smartphone, tablet, laptop, PC). As Maarten Bodewes mentioned, a specific device and even specific OS version can be important. Numbers on one device may have better chance to win against the numbers on another device. Solution is easy: Make the applications on both devices communicate with each other. The applications should swap the generated numbers for each 2nd round: one round app uses its own randomly generated number, the next round it uses the number generated by the peer device, next round - own number, next round - again the peer number. Again, no matter how (cryptographically) good random generators on each device are, the players have equal chances.

mentallurg
  • 2,661
  • 1
  • 17
  • 24