cipher.ink Write a message

Tools ยท Passwords, passphrases and randomness

Random number generator for bytes, UUIDs and dice

Secure random bytes, UUIDs, unbiased integers and dice, plus a live demo of the modulo-bias bug.

Random bytes and UUIDs

A fair integer in a range

Dice and a coin

See modulo bias

Everything is generated in your browser with its cryptographic random number generator. Nothing is sent or stored.

This random number generator makes random bytes, UUIDs, fair integers, dice rolls and coin flips with your browser's cryptographic generator, the same source it uses for TLS keys. Nothing is sent or stored. The last box shows modulo bias happening, which is the mistake that makes many "random number" snippets slightly unfair.

Where the randomness comes from

Every number above comes from crypto.getRandomValues(), which fills an array from the operating system's cryptographically secure generator. The OS seeds it from hardware entropy, and it's designed so that seeing any amount of its output tells you nothing about the next. Math.random() isn't that. It's fast and fine for shuffling a playlist, but its state can be recovered from a short run of outputs, so never use it for keys, tokens, passwords or anything an attacker would want to predict. Random numbers in the browser tells the story of a version of cipher.ink that made exactly that mistake in 2016.

Bytes, UUIDs and what's inside them

For a key, a token or a salt, take bytes. 16 bytes is 128 bits and 32 bytes is 256. cipher.ink's AES keys, IVs and salts are drawn this way (see AES-GCM and PBKDF2). The tool shows the same bytes as hex, as Base64 and as Base64url, the version that's safe in URLs, which cipher.ink links use for the secret key.

A UUID is a 128-bit identifier written as 36 characters. Version 4 is random. Six of its 128 bits are fixed to mark the version and variant, leaving 122 random bits, so a collision between two random v4 UUIDs is astronomically unlikely. Version 7, standardized in RFC 9562 (2024), starts with a 48-bit Unix timestamp in milliseconds and fills the rest with 74 random bits. The timestamp comes first, so v7 UUIDs sort in the order they were created, which keeps database indexes compact. The price is that they reveal roughly when they were made. For a secret that must not be guessed, use plain random bytes instead of a UUID. For a database key where ordering helps, v7 is a good choice.

Fair integers, and why "random % n" is wrong

Getting a number from 1 to 100 out of random bytes looks easy. Take a byte and compute byte % 100. The trouble is that a byte has 256 values, and 256 isn't a multiple of 100. Values 0 to 55 each get three chances (0, 100 and 200 all map to 0, for example), while 56 to 99 get only two. So the first 56 outcomes come up half as often again as the rest. On a real generator the effect can be small, but it isn't zero, and it's a real bug. This site's passphrase generator once had it.

The bias demonstration at the bottom of the tool makes it visible. Leave the box at 200 outcomes and tick the naive method. Outcomes 0 to 55 come up about twice as often as 56 to 199, because 256 = 200 + 56 and the first 56 values get a second chance. Untick it and the same 500,000 draws come out flat, within the noise you'd expect. The fix is rejection sampling. Only accept a byte below the largest multiple of n that fits (here 200), and throw away anything at or above it and draw again. Every outcome then has exactly the same number of chances. cipher.ink's Cipher.randInt does this with 32-bit values (the bias there is tiny to begin with, but the fix costs almost nothing), and every tool on this site uses it. The article on modulo bias shows the code before and after.

Common questions

Is it truly random?

It's as random as your operating system's secure generator, which all browser cryptography relies on. It isn't "true" randomness from a physical device, but no practical attack on these generators is known, and they're continually reseeded from hardware events.

Can I use these for lottery numbers or a raffle?

Yes for a casual draw, since each number is drawn fairly and independently. For anything with money or legal weight, use a process others can audit, because nobody can verify what a browser did.

Why is the largest range 4,294,967,296?

That's 232, the number of values randInt draws at once. For bigger ranges, combine several draws.

Does the dice roller allow repeats?

Yes. Each die is an independent roll, so you can see the same number twice, which is what real dice do.

Further reading

  1. RFC 9562: Universally Unique IDentifiers (UUIDs)
  2. MDN: Crypto.getRandomValues()
  3. W3C Web Crypto API: getRandomValues