【发布时间】:2021-12-11 08:06:04
【问题描述】:
我正在使用 JavaScript BigInts 实现 Miller Rabin primality test。
基本算法没问题 - 我已经完成了,但它需要一个 0 到(正在测试的数字 - 3)范围内的随机数。我无法使用 Math.random() 和扩展,因为我使用的是 BigInt。
这不需要加密安全,只要足够随机,所以我选择生成一串随机选择的十六进制数字并将其转换为 BigInt。
代码如下:
function getRandomBigint(lower, upper) {
// Convert to hex strings so that we know how many digits to generate
let hexDigits = new Array(upper.toString(16).length).fill('');
let rand;
let newDigits;
do {
// Fill the array with random hex digits and convert to a BigInt
newDigits = hexDigits.map(()=>Math.floor(Math.random()*16).toString(16));
rand = BigInt('0x'+newDigits.join(''));
} while (rand < lower || rand > upper);
return rand;
}
这里的问题是生成的数字可能超出范围。这个函数通过迭代来处理这个问题(糟糕地),直到它得到一个范围内的数字。显然,这可能需要很长时间。在实践中,它在传递一个数字之前从未迭代超过几十次,但随机性的本质意味着问题就在“外面”等着咬我!
我可以缩放或截断结果以使其在范围内,而不是迭代,但我担心这会影响随机性。我已经有一些证据表明这并不像它可能的那样随机,但这在这个应用程序中可能无关紧要。
那么,两个问题:
- 这对米勒拉宾来说足够随机吗?
- 如何处理超出范围的结果?
这是一个仅限 JavaScript 的项目 - 请不要使用库。
【问题讨论】:
-
您可以使用
crypto.getRandomValues用随机字节填充适当长度的 Uint8Array(实际上是加密安全的,即使您在这里不关心),然后只调整最后一个字节,或者使用 @ 987654325@,以获得所需的确切范围。然后将字节数组转换为 BigInt(遗憾的是目前不是一个非常有效的操作,但可能没关系)。 -
@Touffy
crypto.getRandomValues可能会改善我最初获得的值的随机性,但这是对最后一个字节的调整带来了麻烦。如果我的原始数字的最高十六进制数字是 1,那么我为该数字获得的几乎每个随机值都需要调整。我的第一次尝试(只是丢弃那个数字)使结果严重偏向值范围的低端。我有另一个想法,我正在测试它可能会简化整个问题。 -
哦,不,getRandomValues 只是一种用随机值填充数组的更简洁的方法,而不是像你正在做的那样使用 Math.random 循环。至于最后一个字节,我的想法是将 Math.random 与您的范围的最大值 + 1 相乘,这样您就始终在您的范围内,而不会出现偏差。
标签: javascript random primes