抗碰撞的雜湊函數真的不會有碰撞嗎?

fcamel
fcamel的程式開發心得
4 min readSep 23, 2019

--

使用 hash function (雜湊函數) 前,必須了解一個很重要的問題: 對兩個不同的數 x、y 來說,hash(x) 等於 hash(y) 的機率有多少?若應用情境是資料結構的 hash table,那麼 hash(x) 和 hash(y) 相等並不嚴重,可以用 chaining 或 open addressing 解。不過這並非本篇想討論的點。

另一方面,像是檢查下載檔案正確性 (例如 Subresource Integrity),或帳戶位置 (例如 Bitcoin addressEthereum address ), 無法容許 hash function 接受兩個不同輸入卻產生一樣的輸出。具有這種「很難找到兩個不同輸入產生相同輸出」的 hash function,我們說它具有 collision resistance (抗碰撞) 的性質。

違反直覺的性質

目前常用的 hash function 像是 SHA-256、SHA-3 是被相信” 有 collision resistance ,而不是有數學證明擔保。另一方面,雖然存在可用數學證明有有此性質的函數,但它們效率太差,並不實用。

以 SHA3 -256 為例,輸入可以是任意大小的資料,輸出固定是 256 bit。直覺來看,將無窮大的空間投影到一個固定大小的空間,怎麼可能沒有碰撞?所以,我們真正關心的是: 資料量多大時,才比較容易發生碰撞?或著說,資料量多少內,幾乎不用擔心碰撞?

生日悖論 (Birthday Paradox)

我們可以用生日悖論來回答此問題。

問題: 一年有 365 天,一個房間裡有多少人後,有過半的機率會有兩人生日一樣?聽起來應該要很多人,但答案卻是 23 人。因為和直觀印象差距很大,所以說是悖論。

由此推廣的一般性問題,就是具 collision resistance 的 hash function 能處理多少筆輸入,而不用擔心有 collision?比方說 SHA-256 的輸入最大可到 2⁶⁴-1 bits,輸出是 256 bits。那麼,SHA-256 處理多少組數字後,會有 collision?

假設攻擊者無法破解 SHA-256,只能從 [0, 2²⁵⁶-1] 裡隨機選 n 個數字亂猜。那麼,差不多要 2¹²⁸ 次才會有 collision。

計算方法

Wikipedia 提供幾種算法,這裡我想說的是另一種直觀解析

假設從數量為 s 的集合抽樣 n 次,n 個取樣都不重覆,可看成有 (a, b), (a, c), … 共 C(n, 2) 個數對,數對裡兩數相等的機率是 1/s。

C(n, 2) 差不多是 n²,期望 n² * 1/s 差不多是 1 的話,得出

  n² / s = 1
→ n² = s
→ n = s^(1/2)

所以長度為 256-bit 的字串,共有 2²⁵⁶ 種字串,差不多取樣 2¹²⁸ 個數後,會出現重覆數。

可以代些數字粗估數量級,感覺一下有多可靠。若期望 n² / 2²⁵⁶ = 1/10¹⁸。計算後得出 n 差不多是 2¹²⁸ / 10⁹,仍然是極大的數字 (比 10²⁹ 大),但估計相撞的機率接近 1/10¹⁸,相當於中獎率百萬分之一的樂透連中三次。

推廣到多個重覆數

同樣問題,求 n 多大時,三個取樣很可能是同一個數。

用同樣思路,共有 C(n, 3) = O(n³) 個數對 (x1, x2, x3),三者一樣的機率是 1/s²。

 /  = 1
=
→ n = s^(2/3)

由此類推,抽樣 n = s^( (k-1) / k ) 時,有 k 個取樣很可能是同一個數。

值域大小和安全性

由以上的分析可知,n bit 的字串,雖然可表示 2^n 個數,卻只有「 2^(n/2)」 的安全性。像是 32 bit 的字串,只要 2¹⁶ = 65536 個字串就能產生 collision。即使用了有 collision resistance 的 hash function,仍需要足夠的 bits 數才安全。

--

--