Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript: Generate a random number within a range using crypto.getRandomValues

Tags:

I understand you can generate a random number in JavaScript within a range using this function:

function getRandomInt (min, max) {     return Math.floor(Math.random() * (max - min + 1)) + min; } 

Courtesy of Ionuț G. Stan here.

What I want to know is if you can generate a better random number in a range using crypto.getRandomValues() instead of Math.random(). I would like to be able to generate a number between 0 and 10 inclusive, or 0 - 1, or even 10 - 5000 inclusive.

You'll note Math.random() produces a number like: 0.8565239671015732.

The getRandomValues API might return something like:

  • 231 with Uint8Array(1)
  • 54328 with Uint16Array(1)
  • 355282741 with Uint32Array(1).

So how to translate that back to a decimal number so I can keep with the same range algorithm above? Or do I need a new algorithm?

Here's the code I tried but it doesn't work too well.

function getRandomInt(min, max) {            // Create byte array and fill with 1 random number     var byteArray = new Uint8Array(1);     window.crypto.getRandomValues(byteArray);      // Convert to decimal     var randomNum = '0.' + byteArray[0].toString();      // Get number in range     randomNum = Math.floor(randomNum * (max - min + 1)) + min;      return randomNum; } 

At the low end (range 0 - 1) it returns more 0's than 1's. What's the best way to do it with getRandomValues()?

Many thanks

like image 423
user2503552 Avatar asked Aug 14 '13 11:08

user2503552


People also ask

How do you generate a random number in JavaScript?

Javascript creates pseudo-random numbers with the function Math. random() . This function takes no parameters and creates a random decimal number between 0 and 1. The returned value may be 0, but it will never be 1.

Can I use Crypto getRandomValues?

getRandomValues() is the only member of the Crypto interface which can be used from an insecure context.


2 Answers

The easiest way is probably by rejection sampling (see http://en.wikipedia.org/wiki/Rejection_sampling). For example, assuming that max - min is less than 256:

function getRandomInt(min, max) {            // Create byte array and fill with 1 random number     var byteArray = new Uint8Array(1);     window.crypto.getRandomValues(byteArray);      var range = max - min + 1;     var max_range = 256;     if (byteArray[0] >= Math.floor(max_range / range) * range)         return getRandomInt(min, max);     return min + (byteArray[0] % range); } 
like image 197
arghbleargh Avatar answered Sep 19 '22 12:09

arghbleargh


IMHO, the easiest way to generate a random number in a [min..max] range with window.crypto.getRandomValues() is described here.

An ECMAScript 2015-syntax code, in case the link is TL;TR:

function getRandomIntInclusive(min, max) {     const randomBuffer = new Uint32Array(1);      window.crypto.getRandomValues(randomBuffer);      let randomNumber = randomBuffer[0] / (0xffffffff + 1);      min = Math.ceil(min);     max = Math.floor(max);     return Math.floor(randomNumber * (max - min + 1)) + min; } 
like image 27
sindilevich Avatar answered Sep 21 '22 12:09

sindilevich