假设我们有一个真正随机的哈希函数,可以将字符串哈希为n位数字。这意味着有2
n种可能的哈希码,并且每个字符串的哈希码都从所有这些可能性中均匀随机选择。
生日悖论特别指出,一旦你看到大约√(2k)个项目,就有50%的碰撞几率,其中k是可能输出的不同数量。在哈希函数哈希到n位输出的情况下,这意味着你需要大约2
n/2次哈希才能获得碰撞。这就是为什么我们通常选择输出256位哈希的原因;这意味着我们需要惊人的2
128 ≈10
38个已哈希的项,才有“合理”的碰撞几率。对于512位哈希,您需要大约2
256次哈希才能获得50%的碰撞几率,而2
256大约等于
已知宇宙中质子的数量。
使用n位哈希函数和k个字符串哈希获取碰撞的概率的确切公式为
1 - 2
n! / (2
kn (2
n - k)!)
这是一个相当棘手的量,但我们可以使用表达式
1 - e
-k2/2n+1
得出此数量的相当近似值。
因此,要获得(大约)概率p的碰撞几率,我们可以解决以下问题
p ≈ 1 - e
-k2/2n+1
1 - p ≈ e
-k2/2n+1
ln(1 - p) ≈ -k
2/2
n+1
-ln(1 - p) ≈ k
2/2
n+1
-2
n+1 ln(1 - p) ≈ k
2
2
(n+1)/2 √(-ln(1 - p)) ≈ k
作为最后一次近似,假设我们正在处理非常小的p选择。然后ln(1 - p) ≈ -p,因此我们可以将其重写为
k ≈ 2
(n+1)/2 √p
请注意,这里仍然有一个巨大的2
(n+1)/2项,因此对于一个256位的哈希函数,该前导项为2
128.5,这是非常巨大的。例如,我们必须看多少个项目才能获得256位哈希函数发生2
-50碰撞的机会?那将是大约
2(256+1)/2 √2-50
= 2257/2 2-50/2
= 2207/2
= 2103.5.
因此,你需要大量的哈希来获得微小的碰撞几率。请注意,2
103.5约为10
31,如果每个哈希计算需要1纳秒,那么你需要的时间比宇宙的寿命还要长。即使经过所有这些,你也只能获得2
-50的成功概率,约为10
-15。
事实上,这正是我们选择如此大的位数用于哈希函数的原因!这使得碰撞发生的机会极其不可能。
(请注意,我们今天拥有的哈希函数实际上并不是真正的随机函数,这就是为什么人们建议不要使用MD5、SHA1和其他已经暴露出安全漏洞的函数。)
希望这能帮到你!