2015-05-01 64 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

請注意,這就是爲什麼密碼哈希需要雙倍輸出,而分塊密碼纔算安全。使用密碼,您不必擔心*碰撞*,因爲這些相同的值會被調用 - 但是您可以使用哈希算法。 –