我正在尝试使用密码学上安全的熵源来对数组进行改组。

我在这里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;
  }
}

此实现正确无误吗?

笔记:
  • 出于我的目的,该数组最多包含约100个元素
  • 运行nodejs v6.10.3 LTS(已编译)
  • 最佳答案

    经过广泛审查后,我得出的结论是,解决方案是正确的,是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;
    }
    

    09-25 18:13