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

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


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);}


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;}


Necromancing.
Well, this is easy to solve.

Consider random number in ranges without crypto-random:

// Returns a random number between min (inclusive) and max (exclusive)function getRandomArbitrary(min, max) {    return Math.random() * (max - min) + min;}/** * Returns a random integer between min (inclusive) and max (inclusive). * The value is no lower than min (or the next integer greater than min * if min isn't an integer) and no greater than max (or the next integer * lower than max if max isn't an integer). * Using Math.round() will give you a non-uniform distribution! */function getRandomInt(min, max) {    min = Math.ceil(min);    max = Math.floor(max);    return Math.floor(Math.random() * (max - min + 1)) + min;}

So all you need to do is replace Math.random with a random from crypt.

So what does Math.random do ?
According to MDN, the Math.random() function returns a floating-point, pseudo-random number in the range 0 to less than 1 (inclusive of 0, but not 1)

So we need a crypto-random number >= 0 and < 1 (not <=).

So, we need a non-negative (aka. UNSIGNED) integer from getRandomValues.
How do we do this?

Simple:Instead of getting an integer, and then doing Math.abs, we just get an UInt:

var randomBuffer = new Int8Array(4); // Int8Array = byte, 1 int = 4 byte = 32 bit window.crypto.getRandomValues(randomBuffer);var dataView = new DataView(array.buffer);var uint = dataView.getUint32();

The shorthand version of which is

var randomBuffer = new Uint32Array(1);(window.crypto || window.msCrypto).getRandomValues(randomBuffer);var uint = randomBuffer[0];

Now all we need to do is divide uint by uint32.MaxValue (aka 0xFFFFFFFF) to get a floating-point number. And because we cannot have 1 in the result-set, we need to divide by (uint32.MaxValue+1) to ensure the result is < 1.
Dividing by (UInt32.MaxValue + 1) works because a JavaScript integer is a 64-bit floating-point number internally, so it is not limited at 32 bit.

function cryptoRand(){    var array = new Int8Array(4);    (window.crypto || window.msCrypto).getRandomValues(array);    var dataView = new DataView(array.buffer);    var uint = dataView.getUint32();    var f = uint / (0xffffffff + 1); // 0xFFFFFFFF = uint32.MaxValue (+1 because Math.random is inclusive of 0, but not 1)     return f;}

the shorthand of which is

function cryptoRand(){    const randomBuffer = new Uint32Array(1);    (window.crypto || window.msCrypto).getRandomValues(randomBuffer);    return ( randomBuffer[0] / (0xffffffff + 1) );}

Now all you need to do is replace Math.random() with cryptoRand() in the above functions.

Note that if crypto.getRandomValues uses the Windows-CryptoAPI on Windows to get the random bytes, you should not consider these values a truly cryptographically secure source of entropy.