我们一直使用Math.random获取4000-64000之间的随机数。:
Math.floor(Math.random() * 60000 + 4000);
我们现在必须使用更加加密的安全随机数生成器来替换它。在搜索了这个问题之后,我们决定一起去 window.crypto.getRandomValues。我无法弄清楚如何使用它来获得特定范围之间的随机数。有人可以帮忙吗。
答案 0 :(得分:6)
对于给定的最小值和最大值,公式描述了如果一次请求u
位则平均使用的位数,如果返回结果则会重试会引入偏差。
幸运的是,最佳策略是立即请求ceil(log2(max - min + 1))
位。我们只能使用crypto.getRandomValues
得到完整的字节,所以如果我们每个函数调用只调用crypto.getRandomValues
,我们能做的最好的就是:
// Generate a random integer r with equal chance in min <= r < max.
function randrange(min, max) {
var range = max - min;
if (range <= 0) {
throw new Exception('max must be larger than min');
}
var requestBytes = Math.ceil(Math.log2(range) / 8);
if (!requestBytes) { // No randomness required
return min;
}
var maxNum = Math.pow(256, requestBytes);
var ar = new Uint8Array(requestBytes);
while (true) {
window.crypto.getRandomValues(ar);
var val = 0;
for (var i = 0;i < requestBytes;i++) {
val = (val << 8) + ar[i];
}
if (val < maxNum - maxNum % range) {
return min + (val % range);
}
}
}
如果生成许多值,可以考虑一些优化,即提前请求更多字节(即更大的数组)。如果你的范围变得更小(比如想要翻转硬币),那么以基于位的方式工作也可能是有益的,即预先请求许多位,然后只用掉你真正需要的随机位。
答案 1 :(得分:1)
Math.random
的简单替换如下所示:
/**
* Return values in the range of [0, 1)
*/
const randomFloat = function () {
const int = window.crypto.getRandomValues(new Uint32Array(1))[0]
return int / 2**32
}
要将其扩展为整数:
/**
* Return integers in the range of [min, max)
*
* @todo check that min is <= max.
*/
const randomInt = function (min, max) {
const range = max - min
return Math.floor(randomFloat() * range + min)
}
要将其扩展为整数数组:
/**
* Generate an array of integers in the range of [min, max).
*/
const randomIntArray = function (length, min, max) {
return new Array(length).fill(0).map(() => randomInt(min, max))
}
生成一个十个整数数组,范围从0到2(含0和2):
randomIntArray(10, 0, 3)
[0, 2, 1, 2, 0, 0, 1, 0, 1, 0]