WheelWhirl
Mathematical Transparency

How Random Is Our Wheel? Cryptographic RNG & Fairness Proof

Unlike online spinners that rely on predictable pseudorandom number generators or introduce silent modulo bias, WheelWhirl uses hardware entropy from the Web Cryptography API.

Live Monte Carlo Chi-Square Simulator

Run up to 10,000 cryptographic spins right now to test actual vs expected uniform probability.

Click “Run Test” to execute a live Monte Carlo trial.

Why Math.random() is Inadequate for Contests

In standard JavaScript, Math.random() uses pseudo-random algorithms like xorshift128+. These algorithms have finite periods and are predictable if a user observes a sequence of results.

By contrast, WheelWhirl uses crypto.getRandomValues(), drawing non-deterministic entropy from OS hardware sources (thermal noise, hardware interrupts, and timing jitter).

Eliminating Modulo Bias via Rejection Sampling

When mapping a 32-bit unsigned integer (range 0 to 4,294,967,295) to N entries, taking val % N introduces bias because 2^32 is rarely divisible by N.

WheelWhirl calculates maxUnbiased = Math.floor(2^32 / N) * N and immediately rejects any random value that falls above that ceiling, guaranteeing strictly equal probability for every slice.

Our Production Rejection Sampling Algorithm (TypeScript)

export function getSecureRandomInt(max: number): number {
  if (max <= 1) return 0;
  const range = 0xffffffff;
  const maxUnbiased = Math.floor(range / max) * max;
  const buffer = new Uint32Array(1);

  while (true) {
    crypto.getRandomValues(buffer);
    const val = buffer[0];
    if (val < maxUnbiased) {
      return val % max; // Zero modulo bias
    }
  }
}