加密安全数组随机播放

Cryptographically secure array shuffle

我正在尝试使用加密安全的熵源对数组进行洗牌。

我在此处 How to randomize (shuffle) a JavaScript array? 发现了一个关于改组数组的类似问题。然而,几乎所有解决方案都使用 Math.random,这是不安全的。 不幸的是,我在这个问题上没有 comment/post 的声誉。

这是我想出的解决方案,它使用 Durstenfeld 混洗与 CSPRNG 配对来生成给定范围内的随机整数(由 random-number-csprng 库提供)。

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 lib, which uses crypto.randomBytesAsync, and is therefore cryptographically secure for most all purposes (see ).

更新:我在此处 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;
}