I want to calculate a random number (1 to 6) from the output of sha256. Can I assurance the probability of 6 abilities is the same?
1 Answers
The approximate way
You don't need to be perfectly even if you can make the unevenness small enough to be undetectable. So you can realistically do this: take the first 128 bits (16 bytes) from the SHA-256 output (or more, if you like), read them in as an unsigned bignum (arbitrary precision integer) using your library of choice, take the remainder modulo 6, and add one. The distribution will not be even—1 will be very slightly more likely than 6—but not distinguishable in practice from an even distribution. The probability of picking 1 is:
$$ {\lfloor 2^{128} \div 6 \rfloor + 1 \over{2^{128}}} $$
...which Wolfram Alpha tells me is about:
$$ 0.166666666666666666666666666666666666667646245292351906256... $$
And the probability of picking 6 is:
$$ {\lfloor 2^{128} \div 6 \rfloor \over{2^{128}}} $$
...which is about this much:
$$ 0.166666666666666666666666666666666666664707509415296187486... $$
These values are only $2^{-128}$ apart, as you can tell algebraically from the expressions above. Good enough for cryptographic purposes.
NIST Special Publication 800-185 (SHA-3 Derived Functions) recommends a similar method for hashing with SHAKE or other variable length output functions into an arbitrary integer range. SP 800-90Ar1 (Recommendation for Random Number Generation Using Deterministic Random Bit Generators), in Section A.5.3, recommends this method as well.
The exact way
Looping over the unsigned bytes in the SHA-256 result byte array, at each step:
- If
result[i] % 8is less than six, return(result[i] % 8) + 1; - Otherwise, if
(result[i] >> 3) % 8is less than six, return((result[i] >> 3) % 8) + 1; - Otherwise, continue on to the next iteration of the loop;
- If you looped through the whole thing, be very suspicious you did something wrong, and if you didn't (!) assign
result := sha256(result)and try again from the top.
Whatever number is returned, it is equally likely as all the other five.
On any given iteration, the chance that iteration will return is 75%, so with 64 attempts, the probability that none of them will return is $(1 - 0.75)^{64} = (2^{-2})^{64} = 2^{-128}$. And if that happens you hit step #4.
- 14,703
- 2
- 33
- 53