diessi.caBlog
November 15, 2016

A Bit on Random Numbers in JavaScript

Math.random() is a JavaScript function that outputs a random number in the range [0, 1) (from 0 up to 1, but doesn’t include 1). It’s the main source of randomness in JavaScript.

Although the output looks random, it’s actually not.

Behind the Scenes

Math.random() uses a pseudo-random number generator (PRNG). Those algorithms work completely determined by a initial value called “seed”.

Given a seed, the sequence of random numbers is deterministic.

Every PRNG requires a seed, which generally is the current system time in milliseconds. Yeah, simple as that.

Speaking of JavaScript language, the PRNG algorithm to deal with the seed is left up to implementors1. The algorithm powering V8’s Math.random() was very poor quality until last year (2015), and implementations between engines were pretty inconsistent.

But the scenario has changed. Currently, JavaScript Engines such as SpiderMonkey, V8, Webkit and Chakra all implements Xorshift128+ algorithm2, faster than the previous one.

Secure Randomness

Although randomness was improved in most JavaScript engines, it isn’t trustworthy as seen that standard PRNGs are highly predictable after a certain period. That’s where Web Crypto API shines!

Web Cryptography API introduces window.crypto.getRandomValues, a cryptographically secure pseudo-random number generator (CSPNG), whose output is impossible or highly improbable to distinguish from a truly random one.

Example

// Array containing two 32-bit integers
const arr = new Int32Array(2);

// Override array integers with random values
const random = crypto.getRandomValues(arr);

for (let i = 0; i < random.length; i++) {
  console.log(random[i]);
}

Of course it comes at a performance cost, so make sure you really need secure random numbers in your program.

Conclusion

If you need apparent randomness–less and speed, you’d probably better off using Math.random(). If you need high-quality randomness, such as in cryptography applications, hashing or statistics, go for a CSPNG such as window.crypto.getRandomValues instead.