Programming Languages - Random Number Generation
Random number generation in programming is divided into two fundamentally different categories:
- Pseudo-Random Number Generators (PRNGs): Fast, deterministic algorithms (like Mersenne Twister or PCG). Given the same initial seed, they produce the exact same sequence of numbers. Designed for simulations, games, and statistical sampling.
- Cryptographically Secure PRNGs (CSPRNGs): Backed by operating system entropy pools (such as
/dev/urandom,getrandom(), or Windows CryptoAPI). Unpredictable and non-reproducible. Required for session tokens, passwords, cryptography, and UUID generation.
Security Rule: Never use general PRNGs (
Math.random(),random.random(),rand()) for security-sensitive tasks, passwords, or authentication tokens. Attackers can reconstruct the internal PRNG state from a few generated outputs and predict all future tokens.
JavaScript & Node.js
PRNG (Fast, Non-Cryptographic)
// Floating point number in [0, 1)
const floatVal = Math.random();
// Integer within range [min, max]
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
CSPRNG (Cryptographically Secure)
// Modern Web API (Browsers & Node.js 19+)
const randomBytes = new Uint8Array(16);
crypto.getRandomValues(randomBytes);
// Node.js 'crypto' module
import crypto from 'node:crypto';
const token = crypto.randomBytes(32).toString('hex');
const secureInt = crypto.randomInt(1, 100); // Thread-safe, unbiased random integer
Python
PRNG (random module)
Uses the Mersenne Twister algorithm (MT19937). Period of .
import random
val = random.random() # Float in [0.0, 1.0)
int_val = random.randint(1, 10) # Integer in [1, 10] (inclusive)
choice = random.choice(['a', 'b', 'c'])
random.shuffle(my_list) # In-place shuffle
CSPRNG (secrets module)
Introduced in Python 3.6 to prevent accidental misuse of random for security:
import secrets
token_hex = secrets.token_hex(16) # 32-character hex token
token_url = secrets.token_urlsafe(32) # Base64 URL-safe token
secure_int = secrets.randbelow(100) # Secure int in [0, 99]
Go
PRNG (math/rand/v2 - Go 1.22+)
Go 1.22 introduced math/rand/v2, which automatically seeds per-thread generators and uses the fast PCG / ChaCha8 algorithms:
package main
import (
"fmt"
"math/rand/v2"
)
func main() {
val := rand.Float64() // Float in [0.0, 1.0)
intVal := rand.IntN(100) // Int in [0, 99]
fmt.Println(val, intVal)
}
CSPRNG (crypto/rand)
Reads directly from kernel entropy:
package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
)
func generateToken(n int) (string, error) {
b := make([]byte, n)
if _, err := rand.Read(b); err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}
Rust
Rust does not include random number generation in the standard library (std), relying on the standard rand crate:
[dependencies]
rand = "0.8"
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
// Random float & range
let n: f64 = rng.gen();
let dice: u32 = rng.gen_range(1..=6);
// Cryptographically secure generation (via OS RNG)
let secure_bytes: [u8; 32] = rand::random();
}
C++ (<random>)
Modern C++11 discarded legacy C rand() (which had poor distribution and tiny ranges) in favor of decoupled engines and distributions:
#include <iostream>
#include <random>
int main() {
// 1. Hardware entropy source for seeding
std::random_device rd;
// 2. Mersenne Twister engine
std::mt19937 gen(rd());
// 3. Uniform integer distribution [1, 100]
std::uniform_int_distribution<int> distrib(1, 100);
for (int i = 0; i < 5; ++i) {
std::cout << distrib(gen) << " ";
}
}
Summary & Security Matrix
| Language | Default PRNG | CSPRNG Module | Underlying Kernel Source |
|---|---|---|---|
| JavaScript | Math.random() (Xoroshiro128+) |
crypto.getRandomValues() |
/dev/urandom / Windows BCrypt |
| Python | random (Mersenne Twister) |
secrets / os.urandom() |
getrandom(2) / /dev/urandom |
| Go | math/rand/v2 (PCG / ChaCha8) |
crypto/rand |
getrandom(2) / /dev/urandom |
| Rust | rand::thread_rng() |
rand::rngs::OsRng |
getrandom syscall |
| C++ | <random> (std::mt19937) |
OS APIs or std::random_device |
Platform-dependent |