我正在尝试使用密码学上安全的熵源来对数组进行改组。
我在这里How to randomize (shuffle) a JavaScript array?找到了一个类似的问题,关于改组数组。但是,几乎所有解决方案都使用Math.random
,这是不安全的。
不幸的是,我没有信誉就这个问题发表评论/发表。
这是我想出的解决方案,它使用Durstenfeld改组和CSPRNG配对,以生成给定范围内的随机整数(由random-number-csprng lib提供)。
const randomNumber = require("random-number-csprng");
async function secureShuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = await randomNumber(0, i);
const temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
此实现正确无误吗?
笔记:
最佳答案
经过广泛审查后,我得出的结论是,解决方案是正确的,是Durstenfeld改组的逐字实现。
但是,Durstenfeld/Fisher-Yates随机播放的随机性与其RNG来源一样。我的解决方案取决于random-number-csprng CSPRNG库,该库使用crypto.randomBytesAsync
,因此在大多数情况下都是加密安全的(请参阅How random is crypto#randomBytes?)。
更新:我在crypto-secure-shuffle处发布了此解决方案的功能等效但效率更高的版本,也可以作为npm软件包提供。这是相关的实现:
const secureRandomInRange = require("random-number-csprng");
async function secureShuffle(array) {
const promises = [];
// asynchronously generate an array of random numbers using a CSPRNG
for (let i = array.length - 1; i > 0; i--) {
promises.push(secureRandomInRange(0, i));
}
const randomNumbers = await Promise.all(promises);
// apply durstenfeld shuffle with previously generated random numbers
for (let i = array.length - 1; i > 0; i--) {
const j = randomNumbers[array.length - i - 1];
const temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}