# The right way to generate a random number in JavaScript

0

Last updated: May 20, 2022.

There’s a lot of reason you’d want to generate a random number in JavaScript: randomizing the appearance of contents, shuffling an array, generating a password, and more.

The most common way is using the in-built `Math.random()`. But `Math.random()` does not generate cryptographically secure random numbers!

Therefore, depending upon the end-goal, methods on the `crypto` interface should also be used to create more strongly random passwords.

## Weakly random but quick with `Math.random()`

The quick and simple way to generate a random number is using the `Math.random()` method. This method generates a number between 0 and 1 (not inclusive of 1).

So, to generate a random number between two values, the return of calling `Math.random()` is modified accordingly:

```/* Use Math.random() to generate a random number (0-10) */

Math.random(); // Returns a value between 0 and <1

Math.floor(Math.random()*10); // Multiples result by 10 and rounds down (result: 0-9)

Math.floor(Math.random()*(10+1)); // Adds one to make return value 0-10```

Externalizing this logic to a function creates a random number generator:

```/* A random number generator using Math.random() */

function getRandomInt(max) {
return Math.floor(Math.random() * (max+1) )
}

getRandomInt(3); // 0, 1, 2 or 3 ```

### What's wrong with `Math.random()`?

The catch with `Math.random()` is that the number it generates is only weakly random.

This isn't a design flaw. When JavaScript was created, `Math.random()` was included to provide a utility function capable of quickly generating random numbers that appear like random to humans.

It was never intended to create cryptographically secure random numbers (i.e. numbers random enough that it is almost impossible for a third party to predict them).

So why hasn't it been replaced?

This is because it fulfills its intended purpose. Instead, there is an alternative.

## Strongly random but slow with `crypto.getRandomValues()`

To create cryptographically secure randoms numbers, use the `crypto` interface available on the global object.

To do so, call the `getRandomValues()` method, passing in a typed array:

```/* Get random values with crypto */

const typedArray = new Uint32Array(5); // Create new typed array object (length 5)

crypto.getRandomValues(typedArray); // Assign random values

console.log(typedArray);
{
"0": 3445426891,
"1": 550747900,
"2": 612279700,
"3": 1488281924,
"4": 2641953635
}

console.log(typeof typedArray);
// object Uint32Array```

To get random values between 0 and maximum value, you can get the remained of `typedArray` divided by the maximum value +1. This works because the remainder returned is never greater than `max`.

```/* A random number generator using window.crypto */

function getRandomInt(max) {
const typedArray = new Uint32Array(1);
crypto.getRandomValues(typedArray);
const res = typedArray % (max+1); // +1 because values should be inclusive of max value

return res;
}

getRandomInt(3); // 0, 1, 2 or 3 ```

## Speed test 🚀

The difference in speed in generating a single random number is significant: `Math.random()` is almost 10x faster than `crypto.getRandomValues()`!

The key takeaway is that there is a speed-to-randomness trade-off: if you want more of one, you will sacrifice the other.

## Takeaway: Choose the right tool for the job!

If speed is important and random-like from a human perspective is good enough, you should probably use `Math.random()`.

According to this rule of thumb, some good use cases for `Math.random()` would be:

• Displaying a random image
• Shuffling a playlist
• In games

However, for tasks where randomness is a priority, using `window.crypto()` is strongly recommended.

For example:

`Math.random()` is something of a misnomer: it generates what appears to us to be a very random number quickly. But its output is not generally considered cryptographically secure. In other words, the randomness of its output is weak enough that it could conceivably be predicted by a third party.
For a greater degree of randomness, use `crypto.getRandomValues()` instead. This does not produce perfectly random values (no generator can) and is slower. But, when security is a priority, it's the better alternative.