You press the "random" button, and the program instantly gives you a number. This looks simple, but it hides a fundamental paradox in computer science: computers are deterministic machines — the same input always produces the same output. So how can they possibly be "truly random"? From lucky wheels to password generators, different tools have completely different requirements for "randomness," and that difference can, in some cases, determine whether your accounts are secure.
1. Why Can't Computers Be "Truly Random"?
Traditional computers are implementations of deterministic Turing machines: all operations follow explicit rules, and the same initial state must lead to the same subsequent state. This means that the output of any algorithm running purely inside a computer is completely determined by its initial value — called a "seed."
If you know the seed, you can predict all subsequent "random" numbers. The number sequences generated by such algorithms look statistically random (passing various randomness tests), but they are fundamentally predictable, periodic pseudo-random sequences. This is why computer science calls them "Pseudo-Random Number Generators" (PRNGs).
Pseudo-randomness isn't a bad thing — for most applications like simulation, games, and statistical sampling, PRNGs are entirely adequate. The problem only arises in scenarios requiring "unpredictability" (cryptography) — where pseudo-randomness becomes a serious security vulnerability.
2. How Pseudo-Random Number Generators Work
2.1 Linear Congruential Generator (LCG)
One of the oldest and simplest PRNGs. The formula is:
X(n+1) = (a × X(n) + c) mod m
Where a (multiplier), c (increment), and m (modulus) are pre-set constants, and X(0) is the seed. Each call computes the next value from the previous one.
LCGs are extremely fast with minimal memory usage, but their quality is limited: the period is finite, and their distribution in multi-dimensional space shows regular hyperplane structures easily detectable by statistical tests. The early ANSI C rand() function used LCG — it's rarely used alone today.
2.2 Mersenne Twister (MT19937)
Proposed by Makoto Matsumoto and Takuji Nishimura in 1998, MT19937 is one of the most widely deployed PRNGs today. Its period reaches 2^19937 − 1 (an astronomically large number), and it passes virtually all statistical randomness tests. Python's random module, Ruby, PHP's rand(), and many other language defaults use Mersenne Twister.
However, Mersenne Twister has a critical weakness: its internal state is 624 32-bit integers. If an attacker observes 624 consecutive output values, they can completely reconstruct the internal state and predict all subsequent outputs. This makes it wholly unsuitable for any security-sensitive application.
2.3 Modern High-Quality PRNGs
A new generation of more modern PRNGs has emerged in recent years: xorshift128+, PCG (Permuted Congruential Generator), xoshiro256**. They offer excellent performance in speed, statistical quality, and period length — but remain equally unsuitable for cryptographic use.
| Algorithm | Period | Speed | Statistical Quality | Cryptographically Secure? |
|---|---|---|---|---|
| LCG (Linear Congruential) | Moderate | Very fast | Adequate | No |
| Mersenne Twister MT19937 | 2^19937−1 | Fast | Excellent | No |
| PCG / xoshiro | 2^128+ | Very fast | Excellent | No |
| ChaCha20 (CSPRNG) | N/A | Fast | Excellent | Yes |
| Hardware RNG (TRNG) | N/A | Slow | True random | Yes |
3. True Randomness: Harvesting Unpredictability from the Physical World
To break free from the deterministic computer's constraints, you need to introduce entropy from the external world — genuinely unpredictable physical events. Operating systems and hardware collect this entropy through multiple means:
- User behavior: Mouse movement trajectories, keyboard keystroke timing — human actions carry extremely high unpredictability
- Hardware interrupt timing: The precise timestamps of disk reads/writes and network packet arrivals, influenced by electromagnetic noise and other physical factors
- CPU timing jitter: Microscopic processor timing variations caused by temperature fluctuations, voltage variation, and other physical phenomena
- Dedicated hardware random number generators (HRNG/TRNG): Hardware that uses quantum effects (thermal noise, radioactive decay, photon behavior) to directly generate truly random bits
Linux's /dev/urandom and /dev/random are the OS-maintained entropy pool interfaces that collect hardware events to provide high-quality random seeds for cryptographic applications. Intel's RDRAND instruction provides hardware random numbers directly at the CPU level.
/dev/random vs /dev/urandom: What's the difference?/dev/random "blocks" when the entropy pool runs low, waiting for more entropy to accumulate. /dev/urandom continues producing output via CSPRNG extension when entropy is low, without blocking. On modern systems, a properly initialized /dev/urandom is sufficiently secure for virtually all applications.
4. Cryptographically Secure Pseudo-Random Number Generators (CSPRNG)
A CSPRNG combines the speed of a PRNG with the unpredictability of entropy sources. It must satisfy two core requirements:
- Next-bit unpredictability: Even knowing all previously output bits, it's impossible to predict the next bit with better than 50% probability.
- Backward security after state compromise: Even if an attacker obtains the CSPRNG's internal state at some point, they cannot work backwards to deduce previously generated outputs.
Common CSPRNGs include:
- ChaCha20-based CSPRNG: The foundation of Linux kernel 4.8+'s
/dev/urandomimplementation, also used by OpenBSD'sarc4random - Fortuna: One of the algorithm foundations for Windows' BCryptGenRandom
- Hash_DRBG / HMAC_DRBG: NIST-standardized CSPRNGs, widely used across security libraries
5. Why Math.random() Must Never Be Used for Passwords
This is one of the most common and most dangerous misconceptions. Nearly every language's built-in "basic random function" — JavaScript's Math.random(), Python's random.random(), PHP's rand() — uses a PRNG, not a CSPRNG.
Taking JavaScript's Math.random() as an example: all major browser implementations use xorshift128+ under the hood. Researchers have demonstrated that by observing just 3 consecutive Math.random() floating-point outputs, you can completely reconstruct the internal state and predict all subsequent "random" numbers.
If you use Math.random() to generate passwords, an attacker who knows your seed (or has observed enough outputs) can enumerate all possible passwords — instead of having to attack the full character space of the password. The correct approach is to use APIs specifically designed for cryptographic purposes:
- JavaScript/Web:
window.crypto.getRandomValues() - Node.js:
crypto.randomBytes() - Python:
secretsmodule (Python 3.6+) - PHP:
random_bytes(),random_int() - Java:
java.security.SecureRandom
Many people write
random.seed(42) when learning to make results reproducible — this is a good practice for teaching and testing. But it directly illustrates the PRNG's nature: once the seed is fixed, all outputs are deterministic. If your seed is guessable (e.g., the current timestamp), an attacker needs only to try a finite set of seed values to recover all your "random" outputs.
6. Randomness Requirements by Use Case
6.1 Games and Entertainment: PRNG Is Sufficient
Dice simulation, lucky wheels, lottery tools, card games — the core requirements here are uniform distribution, speed, and a user experience that feels "fair." Mersenne Twister or modern PRNGs fully satisfy these needs. Even if someone could predict the output, the worst consequence is knowing where the wheel will stop — no security threat exists.
6.2 Statistical Simulation: PRNG with Seed Control
Monte Carlo simulation, statistical sampling, machine learning data splits — require high-quality statistical distributions while also needing reproducibility for verification. Fixed-seed PRNG is the standard approach.
6.3 Cryptography and Security: CSPRNG Required
Password generation, encryption keys, tokens, session IDs, CSRF tokens, one-time passwords (OTP) — the security of these scenarios depends entirely on the unpredictability of the random numbers. No PRNG is acceptable; you must use the OS-provided CSPRNG interface.
6.4 Scientific Experiments: TRNG or High-Quality PRNG
Scenarios that genuinely require "true randomness" (such as quantum mechanics experiments or randomizing participants in clinical trials) use hardware true random number generators, or online services based on physical noise like random.org.
| Use Case | Recommended Type | Example API | Key Requirement |
|---|---|---|---|
| Games / wheels / dice | PRNG | Math.random() | Uniform distribution, speed |
| Statistical simulation | PRNG (fixed seed) | random.seed(n) | Reproducibility, statistical quality |
| Passwords / keys / tokens | CSPRNG | crypto.getRandomValues() | Unpredictability |
| Scientific experiments | TRNG | RDRAND / random.org | True entropy source |
7. The Philosophy and Practical Implications of Randomness
At a deeper level, "true randomness" is a complex question even in physics. In quantum mechanics, certain measurement outcomes (such as the path a photon takes through a polarizer) are considered fundamentally indeterminate — the closest thing to "true randomness" that current physics recognizes. By contrast, classical physics "randomness" (like rolling a die) is theoretically fully predictable: if you know the die's exact initial velocity, air resistance, and the elastic coefficient of the surface, you can calculate the result.
For engineering purposes, however, this philosophical debate is almost irrelevant. What actually matters is: can an attacker predict the output within an acceptable amount of computation time? Modern CSPRNGs are designed to ensure the answer is "no" — not to chase metaphysical "true randomness."
8. Summary
The mechanisms behind how computers generate random numbers — beneath the surface of "press a button, get a number" — contain rich technical layers:
- PRNG (pseudo-random): Deterministic algorithm, fast and statistically good quality, but fundamentally predictable — appropriate for games and simulation, not for cryptography
- TRNG (true random): Collects entropy from the physical world, genuinely unpredictable — slow, used for providing seeds or special requirements
- CSPRNG (cryptographically secure random): Combines PRNG speed with entropy source unpredictability, meets cryptographic security requirements — the only correct choice for passwords, keys, and tokens
Next time you use a password generator or encounter a "random" feature, ask yourself one question: does this scenario need numbers that "look random," or numbers that are "genuinely unpredictable"? That distinction may be exactly where your data security boundary sits.