Last active
December 4, 2024 19:25
-
-
Save sarciszewski/88a7ed143204d17c3e42 to your computer and use it in GitHub Desktop.
Javascript CSPRNG for Integers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* License: WTFPL, CC0, ZAP (Zero For 0wned Anti-copyright Pledge), etc | |
*/ | |
function secure_rand(min, max) { | |
var i = rval = bits = bytes = 0; | |
var range = max - min; | |
if (range < 1) { | |
return min; | |
} | |
if (window.crypto && window.crypto.getRandomValues) { | |
// Calculate Math.ceil(Math.log(range, 2)) using binary operators | |
var tmp = range; | |
/** | |
* mask is a binary string of 1s that we can & (binary AND) with our random | |
* value to reduce the number of lookups | |
*/ | |
var mask = 1; | |
while (tmp > 0) { | |
if (bits % 8 === 0) { | |
bytes++; | |
} | |
bits++; | |
mask = mask << 1 | 1; // 0x00001111 -> 0x00011111 | |
tmp = tmp >>> 1; // 0x01000000 -> 0x00100000 | |
} | |
var values = new Uint8Array(bytes); | |
do { | |
window.crypto.getRandomValues(values); | |
// Turn the random bytes into an integer | |
rval = 0; | |
for (i = 0; i < bytes; i++) { | |
rval |= (values[i] << (8 * i)); | |
} | |
// Apply the mask | |
rval &= mask; | |
// We discard random values outside of the range and try again | |
// rather than reducing by a modulo to avoid introducing bias | |
// to our random numbers. | |
} while (rval > range); | |
// We should return a value in the interval [min, max] | |
return (rval + min); | |
} else { | |
// CSPRNG not available, fail closed | |
throw Error('placeholder; this should be customized with accordance to whatever practices are best for Node.js') | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment