Verifiable Randomness Systems
This document explains a subtle but critical flaw in many game, casino, and simulation systems: modulo bias. It explains why it happens, how it breaks fairness, and how to eliminate it correctly.
A very common pattern in game and backend code looks like this:
maxThe mental model is simple:
Unfortunately, this assumption is mathematically incorrect unless the range size is a power of two.
Modulo bias occurs when the total number of possible random values is not evenly divisible by the target range.
Example:
Assume a random source produces values from 0 to 9 (10 total values). You want a random number in the range 0 to 2 (3 values).
Mapping via modulo produces:
Final counts:
0 appears 4 times1 appears 3 times2 appears 3 timesThe distribution is biased. This bias never disappears, no matter how good the random source is.
Modulo bias:
In casinos, even tiny statistical edges matter.
In games, this can affect:
If your system can be audited or replayed, even small bias is unacceptable.
Developers often argue that the bias is negligible. This is false in systems that are:
If users can verify outcomes or replay them, any bias is a correctness bug, not an optimization tradeoff.
The correct approach to mapping random numbers into ranges is rejection sampling.
Core idea:
Let:
2^64 valuesmaxCompute:
The largest multiple of max that fits inside 2^64. Only accept random values below that threshold.
If a value falls outside it:
The accepted value modulo max is perfectly uniform.
Because every possible output value is backed by the exact same number of input values.
Rejection sampling sounds expensive but is not.
In practice:
1 / maxThis is safe even in high-throughput systems.
Even if you use:
Modulo bias still occurs after the random number is generated. Uniform input does not imply uniform output. Correct mapping matters as much as entropy quality.
A correct implementation must:
Fair randomness is not about better entropy. It is about correct mathematics. Most systems get this wrong. Correct systems are precise, boring, and provable. That is exactly what fairness should look like.
BlockRand always uses the correct mathematics to generate all its random numbers.