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.