PRNGLab

Pseudo-random, properly.

A small reference toolkit for random number generation — the differences between statistical and cryptographic generators, how to seed them correctly, and how to reproduce a sequence when you need to.

0dependencies
4generators
100%client-side

Overview

A pseudo-random number generator (PRNG) is a deterministic algorithm that expands a finite seed into a longer stream of bytes that behaves randomly. Determinism is the whole point: the same seed always produces the same stream, which is what makes Monte Carlo runs, fuzzing corpora and procedural content reproducible.

Determinism is also the trap. Two generators can both look random under a battery of statistical tests while only one of them is safe to derive a key from. Choosing the wrong one is a recurring source of real vulnerabilities, so the distinction is worth being precise about.

Statistical PRNG

xoshiro256**, PCG, Mersenne Twister. Fast, tiny state, excellent distribution. Not safe for secrets: the internal state is recoverable from enough output.

CSPRNG

ChaCha20, HMAC-DRBG. Built to be unpredictable even given the algorithm and previous output. This is what crypto.getRandomValues() gives you.

True entropy

Only the seed needs real entropy. Hardware sources feed the CSPRNG once; the stream from that point is cryptographic.

Generate

Everything below runs in your browser via crypto.getRandomValues(). Nothing is sent to a server, nothing is logged.

press generate
—

Algorithms

FamilyStateSpeedSeekableUse for secrets
xoshiro256**256 bitvery fastnono
PCG64128 bitfastyesno
MT1993719937 bitfastvia initno
ChaCha20256 bitfastyes (counter)yes
HMAC-DRBGvariesmoderatenoyes

"Seekable" means the generator can jump to an arbitrary position in the stream, which is useful for parallel workers each consuming an independent slice.

API

Two primitives cover most needs. Both are seeded from the platform CSPRNG.

// random bytes, the thing you almost always want
const bytes = randomBytes(32);
// → Uint8Array(32)

// unbiased integer in [min, max]
// rejection sampling, no modulo bias
const n = randomInt(1, 100);

Modulo bias is the classic mistake: taking % range from a full-width value makes the low residues slightly more likely. The implementation here rejects out-of-range draws instead.

Notes