【问题标题】:How random is PHP pseudo random, of 4 bytesPHP 伪随机有多随机,4 个字节
【发布时间】:2015-05-01 15:42:56
【问题描述】:

我一直在测试 PHP 中生成值的随机性,并且一直在考虑使用 32 位十六进制来表示给定时间范围内的唯一状态。

我写了这个简单的测试脚本:

$checks = [];
$i = 0;

while (true) {
    $hash = hash('crc32b', openssl_random_pseudo_bytes(4));

    echo $hash . PHP_EOL;

    if (in_array($hash, $checks)) {
        echo 'Copy: ' . $i . PHP_EOL;
        break;
    }

    $i++;

    $checks[] = $hash;
}

令人惊讶的是(对我来说)这个脚本在不到 100,000 次迭代中生成了一个副本,并且低至 1000 次迭代。

我的问题是,我在这里做错了吗?在 40 亿种可能性中,这种频率水平似乎太不可能了。

【问题讨论】:

  • CRC 不是随机的,它是一个校验和
  • 我会说这是意料之中的,因为生日“悖论”。
  • 我已经更新了这个问题,因为 crc32 并不是真正的主题,只是最终产品。
  • 如果这不是主题,请停止在代码中使用 crc32c?

标签: php hash cryptography crc32


【解决方案1】:

不,这并不奇怪,随机数生成器没有任何问题。这是birthday problem。一个房间里只有 23 个人,其中两个生日相同的概率是 50%。这可能是违反直觉的,直到您意识到 23 个人有 253 种可能的配对,因此您可以对两个生日相同的人进行 253 次拍摄。

你在这里做同样的事情。您不会查看何时达到特定的 32 位值。相反,您正在寻找迄今为止创建的任何两个值之间的匹配,这为您提供了更多机会。如果您考虑第 100,000 步,您有 43,000 分之一的机会匹配您迄今为止创建的数字之一,而不是 4,300,000,000 分之一的机会匹配特定数字。在达到 100,000 次的过程中,您已经累积了很多这样的机会。

有关 32 位值的计算,请参阅 this answer here on stackoverflow。平均而言,您只需要大约 93,000 个值即可获得成功。

顺便说一下,在四字节随机值上使用 CRC-32 在这里没有任何意义。无论有没有它,结果都是一样的。您所做的只是将每个 32 位数字唯一地(一对一并映射到)映射到另一个 32 位数字。

【讨论】:

  • 我知道,我不应该在标题中提到算法。这就是我将字节表示为可读的方式。幸运的是,在存储到数据库时,我没有使用这种方法和唯一索引,而是能够按顺序比较带时间戳的记录,所以它只是比较 2 个值。我试图衡量使用 32 位值的局限性,这完美地解释了这一点,谢谢。
  • 请注意,这就是为什么加密哈希需要两倍于块密码的输出才能被认为是安全的。使用密码,您不必担心 冲突,因为这些相同的值被称为 - 但对于散列算法,您会这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-18
相关资源
最近更新 更多