1 前言
前幾天和乙個大佬交流了幾個問題,其中乙個關於id生成的問題推展到了雜湊衝突和乙個與之相關的乙個數學趣題生日悖論。
雜湊的對映壓縮和衝突
生日悖論
crc32的衝突分析
2. 雜湊對映壓縮和衝突
雜湊的本質就是數學,簡單來說雜湊函式實現了各種長度和形式的輸入經過公開的雜湊函式的運算生成乙個固定長度的串,並且這個過程是單向不可逆的,也就是無法從雜湊生成的串逆轉為最初的輸入。
聽起來確實很神奇且有用,像乙個萬能膠囊,在乙個小的範圍內裝了很多不一樣的東西,原來有10mb的檔案或者1gb的檔案經過雜湊運算後都會被對映到乙個固定長度的串,可見壓縮程度之大。
但是又不得不思考另外乙個問題:輸入是無窮盡的,生成的雜湊串長度是固定的,那麼必然面臨著多個不一樣的輸入被對映壓縮為乙個相同的雜湊串,就是無限集合對映有限集合導致的雜湊碰撞或者叫雜湊衝突。
舉個栗子:
假如雜湊串固定長度是二進位制10bit,那麼這個10bit空間可容納的最大數量為2^10=1024,先不說無限輸入集合,假如現在有2000個輸入,在雜湊函式均勻的前提下最少會有2000-1024=976個衝突。
看到這裡,肯定有人會說那不用雜湊了,但是雜湊的壓縮對映和不可逆性帶來的便利確實有很大的吸引力,所以知難而退並不是個好主意。
我們知道冪次**,所以如果把二進位制位數擴充套件到32bit->64bit->128bit->256bit呢,2^32約為42億,2^64約為1800多億億,128和256就更大了,貌似到了這裡開始柳暗花明了,我們將長度增加空間就冪次增加,有效降低了衝突的概率,這也是當前主流的思路和方向。
小結:雜湊函式本身有很多種,底層的實現都有非常複雜的數學邏輯,均勻分布是雜湊函式的乙個重要特徵,筆者才疏學淺並沒有對雜湊函式的數學原理做過多研究。
無限輸入集合向有限集合的壓縮對映是必然會出現碰撞的,解決碰撞的乙個有效方法是增加對映空間長度,理解這一點就足夠進行後面的閱讀了,相信聰明的讀者一定get到筆者的意思了。
3.神奇的生日悖論
前面討論了雜湊衝突的必然性,那麼我們不禁要思考:那我該選擇多少bit的雜湊函式才能避免碰撞呢?
其實面對這個問題的時候,我最開始是這麼想的:使用32bit的雜湊函式這樣還有42億個空間呢,那麼產生雜湊碰撞豈不是42億分之一,貌似可以高枕無憂了,先看乙個有趣的問題:
來自網路
生日悖論是指在不少於 23 個人中至少有兩人生日相同的概率大於 50%。例如在乙個 30 人的小學班級中,存在兩人生日相同的概率為 70%。對於 60 人的大班,這種概率要大於 99%。從引起邏輯矛盾的角度來說,生日悖論並不是一種 「悖論」。但這個數學事實十分反直覺,故稱之為乙個悖論。
確實有一些違背直覺,一年365天怎麼會有那麼多人生日相同呢?然而這卻是個事實。
來實際算一下這個問題:
假設有n個人在同一班級內,在不考慮特殊因素的前提下,例如閏年、雙胞胎,假設一年365日出生概率是平均分布的,計算至少有兩個人在同一日出生的概率是多少?
計算分析過程:
我們從其對立事件進行求解,找到n不斷變化時對應的概率分布,p(n)表示n個人中每個人的生日都不同的概率,先考慮邊界條件當n>365根據鴿巢原理其概率為0,n ≤ 365,則概率為:
在維基百科也有通用計算公式,一起看下:
來自 維基百科
再看下這個曲線和具體的離散化資料:
來自 維基百科
來自 維基百科
結論:人數n=23時至少有兩人生日相同的概率是50.7%,n=30時概率是70%,n=50時概率是97%,這麼看來確實有悖直覺,但是這就是事實。
4. crc32的碰撞概率
我們暫且以32位長度的crc32演算法為例來描述雜湊碰撞的可能性。
簡單來想crc32的空間大小是42億,但是實際上並不**40億左右資料才會出現碰撞,事實這個資料規模並不需要很大就會出現碰撞。
crc32的碰撞問題本質上可以從生日悖論的角度來分析,相當於計算在有n個輸入的情況下出現碰撞的概率。假設現在有k個輸入,不出現衝突的概率計算(將42億用s表示):
第乙個輸入 1/s
第二個輸入 (s-1)/s
第三個輸入 (s-2)/s
第k個輸入 (s-k+1)/s
這個計算過程和生日悖論基本是一樣的,隨著k的增加這個概率值下降非常快,筆者在網上找了乙份crc16-crc64的衝突測試報告,可以看下:
//output.16 count 18134464/18200000output.17 count 18068928/18200000output.18 count 17937856/18200000output.19 count 17675712/18200000output.20 count 17151424/18200000output.21 count 16103198/18200000output.22 count 14061250/18200000output.23 count 10770169/18200000output.24 count 7092360/18200000output.25 count 4153742/18200000output.26 count 2259269/18200000output.27 count 1179721/18200000output.28 count 603421/18200000output.29 count 305089/18200000output.30 count 153722/18200000output.31 count 77254/18200000output.32 count 38638/18200000output.33 count 19232/18200000output.34 count 9652/18200000output.35 count 4914/18200000output.36 count 2343/18200000output.37 count 1204/18200000output.38 count 637/18200000output.39 count 302/18200000output.40 count 152/18200000output.41 count 75/18200000output.42 count 52/18200000output.43 count 21/18200000output.44 count 13/18200000output.45 count 7/18200000output.46 count 1/18200000output.47 count 1/18200000output.48 count 1/18200000output.49 count 0/18200000output.50 count 0/18200000output.51 count 0/18200000output.52 count 0/18200000output.53 count 0/18200000output.54 count 0/18200000output.55 count 0/18200000output.56 count 0/18200000output.57 count 0/18200000output.58 count 0/18200000output.59 count 0/18200000output.60 count 0/18200000output.61 count 0/18200000output.62 count 0/18200000output.63 count 0/18200000output.64 count 0/18200000
輸入時1820w隨機資料,上述資料給出了crcx情況下1820w輸入產生的碰撞數量,可以看到在crc32**現了38638個衝突,在crc49中才出現0碰撞,所以衝突率還是很高的。
5.參考資料
維基百科-生日悖論
crc衝突測試報告
從生日悖論談雜湊碰撞
前幾天和乙個大佬交流了幾個問題,其中乙個關於id生成的問題推展到了雜湊衝突和乙個與之相關的乙個數學趣題生日悖論。雜湊的對映壓縮和衝突 生日悖論 crc32的衝突分析 雜湊的本質就是數學,簡單來說雜湊函式實現了各種長度和形式的輸入經過公開的雜湊函式的運算生成乙個固定長度的串,並且這個過程是單向不可逆的...
python 生日悖論概率計算。
生日悖論指如果乙個房間裡有23 或以上人,那麼至少有兩個人生日相同的 概率大於50 編寫程式,輸出在不同隨機樣本數量下,23 個人中至少兩個人生日相同的概率。from random import randint def list birth list birth for i in range 23 ...
python 生日悖論概率計算。
生日悖論指如果乙個房間裡有23 或以上人,那麼至少有兩個人生日相同的 概率大於50 編寫程式,輸出在不同隨機樣本數量下,23 個人中至少兩個人生日相同的概率。from random import randint def list birth list birth for i in range 23 ...