Random Number Generation: Why Your Computer's 'Random' Is Really Just Very Good Math
In 2008, a Debian Linux bug caused SSH keys to be generated with only 32,767 possible values instead of 2¹⁰²⁴. The bug: a developer had 'fixed' a memory analyzer warning by removing two lines of code that added entropy to the random number generator. The entire internet's SSH security depended on random numbers that weren't random. This is a story about why the source of randomness matters enormously.
Key Takeaways
- Computers can't generate true randomness — they use algorithms (PRNG) seeded by real-world entropy sources
- Math.random() is NOT cryptographically secure — never use it for passwords, tokens, or security-critical code
- Use crypto.getRandomValues() (browser) or
secretsmodule (Python) for security applications - True random number generators (TRNGs) harvest physical entropy: mouse movement, thermal noise, radioactive decay
- The Mersenne Twister (used in Python's random, Ruby's rand) is excellent for simulations but predictable after 624 outputs
How Pseudorandom Number Generators Work
A pseudorandom number generator (PRNG) is a deterministic algorithm that produces a sequence of numbers that appears random but is completely determined by an initial value called the seed. Given the same seed, a PRNG produces the same sequence every time. This is a feature, not a bug — it enables reproducible simulations.
The most widely used PRNG is the Mersenne Twister (MT19937), invented in 1997, which has a period of 2¹⁹⁹³⁷−1 (the generated sequence before repeating). It's used as the default random number generator in Python's random module, Ruby, R, MATLAB, and PHP. It passes virtually all statistical randomness tests — but it's not cryptographically secure because an attacker who observes 624 consecutive outputs can reconstruct the internal state and predict all future outputs.
The Security Danger: Math.random() in JavaScript
❌ NEVER use for security:
// Math.random() — fast but predictable
const token = Math.random().toString(36).substr(2);
// An attacker can predict the next token if they observe enough values
✅ USE for security:
// crypto.getRandomValues() — CSPRNG
const array = new Uint32Array(1);
crypto.getRandomValues(array);
const secureNum = array[0];
// Or use crypto.randomUUID() for UUID v4
const id = crypto.randomUUID();
Where True Randomness Comes From
True random number generators (TRNGs) harvest physical entropy — unpredictable phenomena from the real world. Operating systems maintain an entropy pool fed by: hardware interrupts (timing of keystrokes and mouse movements), disk I/O timing jitter, network packet arrival times, and hardware random number generator instructions (Intel's RDRAND instruction, based on thermal noise in a resistor).
Linux exposes this pool through /dev/random (blocks when entropy is low) and /dev/urandom (never blocks, uses CSPRNG to stretch available entropy). Modern best practice uses /dev/urandom or the getrandom() syscall, which is what Python's secrets module uses.
| Use Case | Recommended | Avoid |
|---|---|---|
| Password generation | Python secrets, crypto.getRandomValues() | random.random(), Math.random() |
| Session tokens / API keys | Python secrets.token_hex(), Node.js crypto | uuid/v4 npm package (check internals) |
| Game dice rolls | Math.random(), Python random.randint() | Overkill to use CSPRNG here |
| Monte Carlo simulation | Mersenne Twister (default) | TRNG — too slow, unnecessary |
| Cryptographic key generation | OS entropy (OpenSSL, libsodium) | Software PRNG ever |
| Lottery / raffle drawing | CSPRNG + verifiable seed (audit trail) | Unverifiable black box PRNG |
Generate Random Numbers
Random Number Generator
Generate random numbers in any range, create random sequences, roll virtual dice, simulate coin flips, and generate random strings with configurable character sets.
Open Random Generator →