2015-05-01 52 views
3

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

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

$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; 
} 

令人惊讶(我)这个脚本在不到10万次的迭代,以及低至1000次迭代产生一个副本。

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

+2

CRC不是随机的,它是一个校验和 –

+2

我想说这是预期的,因为这是一个百日咳“悖论”。 –

+0

我已经更新了这个问题,因为crc32并不是真正的主题,只是最终产品。 – Flosculus

回答

2

不,这并不奇怪,并且随机数发生器没有任何问题。这是birthday problem。一个房间里只有23个人,其中两个同一个生日的概率是50%。这可能是反直觉的,直到你意识到有23个可能的23人配对,所以你在同一个生日的两个人身上得到253个镜头。

你在这里做着同样的事情。你不打算看到你什么时候点击一个特定的32位值。相反,您正在寻找到目前为止创建的任何两个值之间的匹配,这会为您提供更多的机会。如果你考虑第10万步,你就有43,000的机会与你迄今为止创建的数字中的一个相匹配,而不是与4,300,000,000匹配一个特定数字的机会相匹配。在运行达到100,000人时,你已经增加了很多机会。对于32位值的计算,参见this answer here on stackoverflow。平均而言,您只需要大约93,000个值即可获得成功。

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

+0

我知道,我不应该在标题中提到算法。这就是我如何将字节表示为可读的内容。幸运的是,当存储到数据库时,我不使用具有唯一索引的此方法,而是可以顺序比较时间戳记录,因此它只是两个值的比较。我试图衡量使用32位值的限制,这完全解释了它,谢谢。 – Flosculus

+0

请注意,这就是为什么密码哈希需要双倍输出,而分块密码才算安全。使用密码,您不必担心*碰撞*,因为这些相同的值会被调用 - 但是您可以使用哈希算法。 –