代码之家  ›  专栏  ›  技术社区  ›  David

加密安全阵列洗牌

  •  5
  • David  · 技术社区  · 7 年前

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

    我发现了一个类似的问题,关于洗牌数组 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(传输)
    1 回复  |  直到 7 年前
        1
  •  3
  •   David    7 年前

    在全面回顾之后,我得出结论,解决方案是正确的,是Durstenfeld shuffle的逐字实现。

    然而,Durstenfeld/Fisher-Yates洗牌只是随机的,因为它是RNG来源。我的解决方案取决于 random-number-csprng CSPRNG lib,使用 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;
    }