A software coin flip should be random. That sounds like a statement nobody would argue with, but it hides a deep and technically interesting question: what does random actually mean? Computers are deterministic machines. They do exactly what you tell them. How can a machine that follows strict rules produce unpredictable output?
The answer is: carefully, with a specific class of algorithm called a cryptographically secure pseudorandom number generator — a CSPRNG. This is what FLIPSTREAK uses to decide every single coin flip in the game. It is the same class of randomness that secures your banking session, your TLS handshake, your Signal messages, and your Bitcoin wallet. Let's unpack why it is fair, how it works, and why it is actually fairer than a real coin.
Three levels of "random" in software
Not all randomness is equal. There are three common categories of random number generation in software, and they are not interchangeable:
1. Statistical RNG (e.g., Math.random() in most languages)
These are fast, deterministic algorithms that produce output that looks random to statistical tests. They use simple math — typically a linear congruential generator or a Mersenne Twister — seeded with a starting value. If you know the seed, you can predict every future output perfectly. Useful for video game effects, dice rolls in single-player games, procedurally generated terrain. Not safe for anything where predictability is a security problem.
JavaScript's built-in Math.random() is in this category. It is not cryptographically safe, and a motivated attacker who sees a few outputs can predict future ones. That is why FLIPSTREAK does not use it for anything that matters.
2. Cryptographic PRNG (CSPRNG)
A CSPRNG is a deterministic algorithm — it still runs on a computer, and the same inputs produce the same outputs — but it is constructed so that even with enormous compute budgets, seeing some past outputs gives you effectively no information about future outputs. Modern CSPRNGs use well-studied cryptographic primitives (AES in counter mode, ChaCha20, SHA-based constructions) to mix entropy from the operating system's entropy pool into an output stream that is computationally indistinguishable from true random noise.
This is what FLIPSTREAK uses, through the crypto.getRandomValues Web API in the browser and crypto.getRandomValues in the Cloudflare Worker runtime on the server. Both ultimately draw from the operating system's entropy sources. We'll get back to this in a minute.
3. True RNG (hardware)
Some chips have physical random number generators that sample real quantum or thermal noise. Intel's RDRAND instruction, for example, uses thermal noise on the CPU die as an entropy source. True RNGs produce output that is provably unpredictable from any physical theory, not just mathematically hard to predict. They are slower and not available on every device, so they are typically used to seed a CSPRNG, which then spits out higher-volume output from that seed.
What is entropy, really?
Entropy, in the information-theoretic sense, is a measure of uncertainty. A fair coin flip has exactly 1 bit of entropy — one binary decision, two equally likely outcomes. A six-sided die has about 2.585 bits. The phrase "I will go out tomorrow unless it rains, 30% chance of rain" carries about 0.88 bits of entropy, because one outcome is more likely than the other. The formula is Shannon's: H = −Σ p(x) log2 p(x).
For randomness to be real, it has to come from somewhere with genuine physical unpredictability. Computers gather entropy from several places:
- Hardware noise — thermal fluctuations, voltage jitter
- Timing jitter — microsecond variations in disk seeks, network packets, interrupt arrival times
- User input — mouse movements, keystroke timings (legacy, mostly on interactive desktops)
- Environmental sensors — camera noise, microphone noise (rarely used by the OS)
The operating system continuously pools these entropy sources, blends them through cryptographic hash functions, and makes the result available through interfaces like /dev/urandom on Linux and BCryptGenRandom on Windows. When a program asks for random bytes, the OS pulls from this pool. The result is not predictable to anyone — not even someone with full source-code access, because the entropy sources are physical.
The ChaCha20 engine inside modern browsers
The specific CSPRNG used by most modern browsers (Chrome, Firefox, Safari, Edge) is based on ChaCha20 — a stream cipher designed by Daniel J. Bernstein in 2008. ChaCha20 takes a 256-bit key and a 64-bit counter and produces a stream of pseudorandom bits by mixing them through 20 rounds of additions, rotations, and XORs. The key is re-seeded frequently from the OS entropy pool, which ensures that even if a huge volume of output is generated, the attacker cannot back-derive the key.
The security of this design has been analyzed extensively by the cryptographic community. It is used in TLS 1.3, in WireGuard, in modern SSH, and in the disk encryption of most smartphones. As of 2026, no practical attack against ChaCha20 exists. When you call crypto.getRandomValues(new Uint8Array(1)) in a browser, you are pulling one byte out of this stream.
How FLIPSTREAK uses it
Every coin flip in FLIPSTREAK is decided on the server, in a Cloudflare Worker, by this exact function call:
const bytes = new Uint8Array(1);
crypto.getRandomValues(bytes);
const result = (bytes[0] & 1) === 0 ? 'heads' : 'tails';
The code reads one byte of cryptographic randomness, takes its lowest bit, and uses that bit as the result. Because the source byte is uniformly distributed over 0–255, the lowest bit is uniformly 0 or 1 — a perfect 50/50 split. There is no seed the client can manipulate, no weighted distribution, no hidden state, no "adjustment" based on your streak. The bit is what the bit is.
This is important because it means FLIPSTREAK is provably fair in a way that physical coins simply cannot be. As we've discussed in the article on whether real coin flips are 50/50, physical coins are biased toward their starting face about 51% of the time due to the way human thumbs spin them. Digital coins have no thumb.
Could an attacker predict the next flip?
To predict the next flip, an attacker would need to:
- Obtain the current internal state of the server's CSPRNG (a 256-bit ChaCha20 key and counter, or equivalent)
- Do so faster than the OS re-seeds the pool (typically every few seconds to minutes)
- And either break the ChaCha20 algorithm itself or break the operating system's entropy-collection mechanism
Each of these is hard. In combination, they are effectively impossible with any known technology. The state of the art in CSPRNG attacks assumes side-channel access to the machine — the attacker needs to physically own the server. And even then, after a single re-seed event, past outputs don't help you predict future ones (a property called forward secrecy).
In practice, the attacker is going to have a much easier time attacking literally any other layer of the system. The coin flip is the hardest thing to cheat in FLIPSTREAK.
Why this is fairer than a physical coin
A summary of the comparison, which is the surprising punchline of this article:
| Source | Fairness (how close to 50/50) | Predictability |
|---|---|---|
| Human-flipped physical coin (caught) | 51/49 (starting-face bias) | Minor — skilled flippers can bias |
| Human-spun physical coin | 80/20 in some cases | Predictable — heavy face falls |
| Math.random() in JavaScript | ≈50/50 statistically | Predictable to a determined attacker |
| crypto.getRandomValues (CSPRNG) | 50/50 to many decimal places | Unpredictable to all known attackers |
This is not a marketing claim. It is what the primitives actually deliver. A coin flip executed by a properly-seeded CSPRNG is genuinely more even-handed than any physical coin ever tossed by a human thumb. If the only thing you cared about was fairness, you would prefer the digital coin every time.
So what's left of the romance?
Something is lost in moving from metal to math. The feel of a coin in your palm, the small wobble in the air, the sound of it hitting the floor — none of that has an analog in a CSPRNG call. FLIPSTREAK tries to recover it through animation, sound, weight: the coin in the game spins for 1100 milliseconds with a small settling bounce, not because the math needs the delay but because your brain does.
The math would be content to tell you the result in zero milliseconds. The experience needs a coin that feels like a coin. So the coin feels like a coin, and the randomness that decides its landing is sharper and cleaner than anything your thumb could produce. That is the trade, and it is a good trade.
Further reading
- MDN: Crypto.getRandomValues() reference
- RFC 8439: The ChaCha20 and Poly1305 specifications
- random.org: Introduction to randomness — an approachable read, though random.org uses atmospheric noise which is a true RNG, not a CSPRNG
For the other side of the coin (sorry) — the physics of why real flipped coins are slightly biased — see our article on the Diaconis paper. For why past flips don't predict future flips no matter how much your gut insists they should, see the gambler's fallacy explained. And for the cold probabilities of streaks of any length, see the full odds table.
The coin you flip on FLIPSTREAK is decided by mathematics so hardened that TLS encryption trusts its life to the same primitives. It is as close to a Platonic 50/50 as engineering can produce. Go see what you can do with it.



