Pseudo-Random vs Cryptographic Randomness
Two generators, two guarantees, and the surprisingly small list of cases where the difference bites.
Every browser ships two random number generators. One is fast, deterministic given its internal state, and available as `Math.random()`. The other is slower, unpredictable, and available as `crypto.getRandomValues()`.
The usual framing — that one is real randomness and the other is fake — is wrong in both directions. `Math.random()` produces genuinely well-distributed output, and `crypto.getRandomValues()` is not drawing from cosmic noise. The difference is about predictability, not about quality of distribution.
This page covers what each one actually guarantees, and gives an honest account of when the difference matters and when it does not.
What a pseudo-random generator is
A pseudo-random generator is a deterministic function. It holds an internal state, and each call transforms that state and returns a value derived from it. Given the same starting state, it produces the same sequence forever — that is what pseudo means.
Modern implementations are good at the thing they are designed for: producing output that passes statistical tests for uniformity, independence and lack of pattern. The generator behind `Math.random()` in current browsers is a well-regarded design with an enormous period, and its output is uniform to any measurement you would care to make.
What it does not provide is unpredictability. Given enough consecutive outputs, the internal state of a non-cryptographic generator can be recovered, and once recovered every future output is known. The number of outputs required is small — for common designs, a handful.
- Deterministic: same state, same sequence, every time.
- Statistically excellent: passes uniformity and independence tests.
- Fast: no system call, no entropy pool.
- Predictable: the state can be recovered from a short run of outputs.
What a cryptographic generator adds
A cryptographically secure generator is also deterministic internally — it is not sampling physical noise for every call. What it adds is a design guarantee: even given a long run of outputs, an attacker cannot recover the internal state or predict the next value with better than negligible advantage.
It gets its unpredictability from being seeded by the operating system's entropy pool, which collects genuine physical unpredictability from sources like timing jitter, and from being built on primitives where reversing the output to recover the state is computationally infeasible.
The cost is a system call and a slower path. On modern hardware that cost is measured in microseconds, which is why the argument for using it by default is stronger than it used to be.
When the difference actually matters
Honestly, less often than security-minded advice implies. For a spinner wheel deciding what to have for dinner, a predictable generator makes no practical difference, because nobody is going to recover your browser's PRNG state in order to influence what you eat.
It matters when someone benefits from predicting the outcome. Passwords, session tokens, and any draw where knowing the result early confers an advantage — a giveaway with a valuable prize, a game where a participant could act on foreknowledge. In those cases a predictable generator is a genuine vulnerability, not a theoretical one.
It also matters for a reason that has nothing to do with attacks: it is a statement of intent. A site that says its draws are fair and uses a predictable generator has made a claim it cannot fully support, and the cost of using the unpredictable one is a few microseconds.
Where each one is appropriate
- Password or token generation: cryptographic, always. This is the case it exists for.
- A prize draw with real value: cryptographic — someone benefits from predicting it.
- A dinner wheel or a party game: either works; nothing turns on predictability.
- A reproducible published draw: neither — you want a seeded generator, deliberately.
The third case: deliberately reproducible
There is a situation where you want a predictable generator on purpose, and it is easy to miss because it sits outside the usual framing. A draw that somebody has to be able to verify afterwards must be reproducible, and reproducible means predictable given the seed.
Publishing a seed and an entrant list lets any reader re-run your draw and confirm the result. That is a strong fairness property and it is completely incompatible with unpredictability: anyone who has the seed knows the outcome.
So the choice is not two-way. It is: unpredictable when nobody should be able to anticipate the result, reproducible when everybody should be able to check it, and either when it does not matter.
What neither of them is
Neither generator is drawing from quantum noise per call, and it is worth saying so because the marketing language around randomness encourages the opposite impression. Both produce output from an algorithm; the cryptographic one is seeded by system entropy and designed so its state cannot be inferred.
There are hardware random number generators that do sample physical processes directly, and some CPUs expose one. Operating systems mix that into their entropy pools where available. From inside a browser you do not choose between them — you get whatever the platform provides through one API.
The practical consequence is that the guarantee you rely on is a design guarantee about predictability, not a metaphysical claim about the source. That is a weaker-sounding statement and a more accurate one.
Frequently asked questions
Is Math.random() bad?
No. Its output is well-distributed and passes statistical tests. What it lacks is unpredictability — its internal state can be recovered from a short run of outputs.
Is crypto.getRandomValues() sampling physical noise?
Not per call. It is a deterministic algorithm seeded from the operating system's entropy pool and designed so its state cannot be inferred from its output.
When does the difference genuinely matter?
When someone benefits from predicting the outcome — passwords, tokens, valuable prize draws. For a dinner wheel it makes no practical difference.
How much slower is the cryptographic one?
Microseconds per call on modern hardware. Slow enough to notice in a tight loop generating millions of values; irrelevant for anything a page does interactively.
Why would I ever want a predictable generator?
For a draw somebody has to verify. Publishing a seed lets anyone re-run and confirm the result, which requires reproducibility and therefore predictability.
Can I tell which one a website uses?
Only by reading its source. There is no observable difference in the output — that is precisely the point.
Does using the cryptographic one make a draw fair?
It removes one class of problem. Fairness also depends on the algorithm, the entrant list, and whether anyone re-ran the draw until they liked it.
Which does this site use?
crypto.getRandomValues for every tool except the seed generator, which uses a seeded pseudo-random generator on purpose so its draws can be reproduced.
Tools that use this
Related guides
Web Crypto getRandomValues: A Reference
What the browser API guarantees, what it does not, and the limits worth knowing.
Entropy and Password Strength
Bits of entropy, in plain terms, and why a longer random password beats a cleverer one.
Which Randomness Each Tool Here Uses
A tool-by-tool table of the exact draw behind every generator on this site.