True Random vs. Pseudo-Random: What Actually Makes a Generator Random
Not all 'random' is created equal. Here's what's actually happening under the hood — and why it matters.
Two different meanings of 'random'
Almost every programming language ships a built-in random function — JavaScript's Math.random(), for example. These are fast, convenient, and completely unsuitable for anything where fairness or unpredictability actually matters. Understanding why requires knowing what's really happening when a computer generates a 'random' number.
Pseudo-random number generators (PRNGs)
A PRNG doesn't generate true randomness at all — it runs a deterministic mathematical formula, seeded by some starting value, that produces a sequence of numbers which looks statistically random but is entirely reproducible if you know the seed and the algorithm. Given the same seed, a PRNG will always produce the exact same sequence of 'random' numbers, every time.
This isn't a flaw — for most everyday uses (a video game's random loot drop, a UI animation's random delay), fast and 'random enough' is exactly what's needed, and PRNGs are the right tool. The problem appears when predictability actually matters: if an attacker can guess or reconstruct the seed, they can predict every 'random' value the PRNG will ever produce.
Cryptographically secure random (CSPRNG)
A cryptographically secure pseudo-random number generator is built differently: it draws entropy from unpredictable physical sources your operating system collects — things like precise hardware timing jitter, mouse movement, and other low-level system noise — and processes it through algorithms specifically designed to resist prediction, even by someone who can see part of the output sequence.
Every browser exposes this through the Web Crypto API's crypto.getRandomValues() function, which is what every generator on Xrandom uses instead of Math.random(). It's the same class of random source used for generating encryption keys and security tokens — genuinely appropriate for anything from a raffle draw to a password.
The other half of fairness: unbiased range mapping
A secure random source alone isn't enough to guarantee fairness — how you convert that randomness into a specific range matters too. A common but subtly flawed approach is Math.floor(Math.random() * range), which — even setting aside the PRNG predictability issue — can quietly favor lower numbers whenever the range doesn't divide evenly into the generator's output space.
Xrandom avoids this using rejection sampling: instead of squeezing a random value into your range with modulo math, it discards any draw that would introduce bias and tries again. The result is that every integer in your chosen range has exactly, provably equal odds — whether you're drawing from 1–6 or 1–37.
When does this actually matter?
For a lot of casual randomness — which meme to show next, a random UI shuffle — the difference between PRNG and CSPRNG is invisible and irrelevant. It matters when:
- Money or prizes are on the line (raffles, giveaways, lottery-style draws)
- Fairness needs to be defensible if questioned (classroom draws, team assignments, audits)
- Security is involved (passwords, tokens, keys — see Xrandom's Password Generator and Raw Random Bytes Generator)
In all of these cases, the difference between 'looks random' and 'is provably unpredictable' is exactly the difference that matters.