11

Is it mathematically possible to take a SHA256 hash and turn it into a 0-99 number where each number in 0-99 range is equally likely to be picked?

As a 256 bit hash means the highest value possible is 2^256, this is not a nice or "round" number for the purposes of simplifying a hash down to ranges more natural for humans.

Mike Edward Moras
  • 18,161
  • 12
  • 87
  • 240
John T
  • 487
  • 2
  • 4
  • 10

3 Answers3

16

If you mean exactly as likely, no, because the number of possible hashes is not a multiple of $100$. This is assuming all the hashes are exactly equally likely. You can come very close just by taking $SHA256 hash \pmod {100}$ This will be within one part in $\frac {2^{256}}{100}$, which is a very small number. If you want truly equal, check that the hash is in the range $[0,100\lfloor \frac {2^{256}}{100}\rfloor)$ and take it $\pmod {100}$ If it is above that, hash something else and try again. Your odds of failing the check are very small, and your odds of failing twice are very small.

In the general case: if one wants a result in the range $0..n\text{-}1$ then use $\bmod n$ and discard if the output $>n\lfloor \frac {2^{256}}{n}\rfloor$ and try another input. This is called the discarding technique; it is commonly used to extract a number in a range from a (pseudo) random number generator.

Maarten Bodewes
  • 96,351
  • 14
  • 169
  • 323
Ross Millikan
  • 276
  • 2
  • 7
4

No, it is not possible to get exactly equal probabilities for a deterministic mapping from all 256-bit numbers to the range 0-99.

However, you can ask whether it matters, since a bias on the order of $2^{-256}$ is undetectable. A mapping that took the 256-bit number modulo 100 and refused the inputs less than $2^{256} \bmod 100$ would be unbiased and would never fail in practice.

You can also get the next best thing – probabilities that are not exactly equal, but for which no one knows which of the numbers 0-99 is biased which way. For example, you can define the mapping using another SHA-256 iteration like so:

  1. Take the SHA-256 hash of the initial hash concatenated with the number 1 (e.g. in ASCII): $H(h||1)$. If this is at least $2^{256} \bmod 100$, return it modulo 100.
  2. Otherwise increment the counter and calculate $H(h||2)$, doing the same check.
  3. Continue as long as necessary (i.e. in practice you never need to go further than the first step).

Since we don't know which $h$ (if any) produce $H(h||1) < 36$, we don't know the resulting $H(h||2)$.

otus
  • 32,462
  • 5
  • 75
  • 167
-1

You could simply just XOR all the bytes of the hash to one single byte (lets call it $b$ for now): $b = hash_0 \oplus hash_1 \oplus ... \oplus hash_{31}$. $b \in [0, 255]$. Calculate $b' = b / 2.55$. $b' \in [0, 100]$.

marstato
  • 518
  • 3
  • 14