Hash函数碰撞概率公式
生日问题
这个问题在数学上早有原型,叫做"生日问题"(birthday problem):一个班级需要有多少人,才能保证每个同学的生日都不一样?
答案很出人意料。如果至少两个同学生日相同的概率不超过5%,那么这个班只能有7个人。事实上,一个23人的班级有50%的概率,至少两个同学生日相同;50人班级有97%的概率,70人的班级则是99.9%的概率(计算方法见后文)。
这意味着,如果哈希值的取值空间是365,只要计算23个哈希值,就有50%的可能产生碰撞。也就是说,哈希碰撞的可能性,远比想象的高。实际上,有一个近似的公式。
上面公式可以算出,50% 的哈希碰撞概率所需要的计算次数,N 表示哈希的取值空间。生日问题的 N 就是365,算出来是 23.9。这个公式告诉我们,哈希碰撞所需耗费的计算次数,跟取值空间的平方根是一个数量级。
这种利用哈希空间不足够大,而制造碰撞的攻击方法,就被称为生日攻击(birthday attack)。
生日问题数学推导
这一节给出生日攻击的数学推导。
至少两个人生日相同的概率,可以先算出所有人生日互不相同的概率,再用 1 减去这个概率。
我们把这个问题设想成,每个人排队依次进入一个房间。第一个进入房间的人,与房间里已有的人(0人),生日都不相同的概率是 365 365 \frac{365}{365} 365365;第二个进入房间的人,生日独一无二的概率是 364 365 \frac{364}{365} 365364;第三个人是 363 365 \frac{363}{365} 365363,以此类推。
因此,n个人(
n
<
366
n<366
n<366)的生日都不相同的概率,就是下面的公式。
p
‾
(
n
)
=
1
∗
364
365
∗
363
365
∗
.
.
.
.
∗
365
−
n
+
1
365
\overline{p}(n)=1\ast\frac{364}{365}\ast\frac{363}{365}\ast....\ast\frac{365-n+1}{365}
p(n)=1∗365364∗365363∗....∗365365−n+1
那么,至少有两个人生日相同的概率,就是 1 减去上面的公式。
p
(
n
)
=
1
−
p
‾
(
n
)
p(n)=1-\overline{p}(n)
p(n)=1−p(n)
哈希碰撞的公式
在高数中,根据泰勒公式,指数函数 e x e^x ex 可以用多项式展开。
e x p ( x ) = ∑ k = 0 ∞ x k k ! = 1 + x + x 2 2 + x 3 6 + . . . exp(x)=\sum_{k=0}^{\infty}\frac{x^k}{k!}=1+x+\frac{x^2}{2}+\frac{x^3}{6}+... exp(x)=∑k=0∞k!xk=1+x+2x2+6x3+...
当x是一个极小值的时候,那么上面的公式近似等于下面的形式。
e
x
≈
1
+
x
e^x \approx 1+x
ex≈1+x
现在把生日问题的
1
365
\frac{1}{365}
3651带入:
364
365
=
1
−
1
365
≈
e
−
1
365
\frac{364}{365}=1-\frac{1}{365}\approx e^{-\frac{1}{365}}
365364=1−3651≈e−3651
所以
p
‾
(
n
)
\overline{p}(n)
p(n)可以写成如下的公式:
p
‾
(
n
)
≈
1
∗
e
−
1
365
∗
e
−
2
365
∗
.
.
.
∗
e
−
n
−
1
365
\overline{p}(n)\approx 1\ast e^{-\frac{1}{365}}\ast e^{-\frac{2}{365}}\ast ...\ast e^{-\frac{n-1}{365}}
p(n)≈1∗e−3651∗e−3652∗...∗e−365n−1
化简为:
p
‾
(
n
)
=
e
−
n
(
n
−
1
)
730
\overline{p}(n)=e^{-\frac{n(n-1)}{730}}
p(n)=e−730n(n−1)
所以 p ( n ) = 1 − p ‾ ( n ) = 1 − e − n ( n − 1 ) 730 p(n)=1-\overline{p}(n)=1-e^{-\frac{n(n-1)}{730}} p(n)=1−p(n)=1−e−730n(n−1)
假设d为取值空间(生日问题中是365),那么就得到一般化的公式:
p
(
n
,
d
)
≈
1
−
e
−
n
(
n
−
1
)
2
d
p(n,d)\approx 1-e^{-\frac{n(n-1)}{2d}}
p(n,d)≈1−e−2dn(n−1)