从生日悖论谈哈希碰撞

哈希映射压缩和冲突

 

hash算法有两个基本特点:可重复和不可逆。即不同的原文理论上有可能得到相同的hash值;也正是因为如此,从hash值反推出原文是不可能的。
引用一段百度百科
所有散列函数都有如下一个基本特性:如果两个散列值是不相同的(根据同一函数),那么这两个散列值的原始输入也是不相同的。这个特性是散列函数具有确定性的结果。但另一方面,散列函数的输入和输出不是一一对应的,如果两个散列值相同,两个输入值很可能是相同的,但并不能绝对肯定二者一定相等。输入一些数据计算出散列值,然后部分改变输入值,一个具有强混淆特性的散列函数会产生一个完全不同的散列值。

简单来说哈希函数实现了各种长度和形式的输入经过公开的哈希函数的运算生成一个固定长度的串,并且这个过程是单向不可逆的

 

听起来确实很神奇且有用,像一个万能胶囊,在一个小的范围内装了很多不一样的东西,原来有10MB的文件或者1GB的文件经过哈希运算后都会被映射到一个固定长度的串,可见压缩程度之大。

 

但是又不得不思考另外一个问题:输入是无穷尽的,生成的哈希串长度是固定的,那么必然面临着多个不一样的输入被映射压缩为一个相同的哈希串,就是无限集合映射有限集合导致的哈希碰撞或者叫哈希冲突

如何解决?

无限输入集合向有限集合的压缩映射是必然会出现碰撞的,解决碰撞的一个有效方法是增加映射空间长度

 

生日悖论

前面讨论了哈希冲突的必然性,那么我们不禁要思考:那我该选择多少bit的哈希函数才能避免碰撞呢?

其实面对这个问题的时候,我最开始是这么想的:使用32bit的哈希函数这样还有42亿个空间呢,那么产生哈希碰撞岂不是42亿分之一,貌似可以高枕无忧了,先看一个有趣的问题:

生日悖论是指在不少于 23 个人中至少有两人生日相同的概率大于 50%。例如在一个 30 人的小学班级中,存在两人生日相同的概率为 70%。对于 60 人的大班,这种概率要大于 99%。从引起逻辑矛盾的角度来说,生日悖论并不是一种 “悖论”。但这个数学事实十分反直觉,故称之为一个悖论。

 

 

xp
20 0.4114
25 0.5687
30 0.7305
35 0.8144
40 0.8912
45 0.9410
50 0.9704
55 0.9863
60 0.9941

从上述表格中不难看出当人数达到60时,概率就会接近于1。

计算方法如下:

preview
 

CRC32的碰撞概率

我们暂且以32位长度的CRC32算法为例来描述哈希碰撞的可能性。

简单来想CRC32的空间大小是42亿(2^32,md5是128),但是实际上并不代码40亿左右数据才会出现碰撞,事实这个数据规模并不需要很大就会出现碰撞。

CRC32的碰撞问题本质上可以从生日悖论的角度来分析,相当于计算在有N个输入的情况下出现碰撞的概率。假设现在有K个输入,不出现冲突的概率计算(将42亿用S表示):

  • 第一个输入 1/S
  • 第二个输入 (S-1)/S
  • 第三个输入 (S-2)/S
  • ......
  • 第k个输入 (S-k+1)/S

这个计算过程和生日悖论基本是一样的,随着K的增加这个概率值下降非常快,笔者在网上找了一份CRC16-CRC64的冲突测试报告,可以看下:

//http://www.backplane.com/matt/crc64.html
output.16 Count 18134464/18200000
output.17 Count 18068928/18200000
output.18 Count 17937856/18200000
output.19 Count 17675712/18200000
output.20 Count 17151424/18200000
output.21 Count 16103198/18200000
output.22 Count 14061250/18200000
output.23 Count 10770169/18200000
output.24 Count 7092360/18200000
output.25 Count 4153742/18200000
output.26 Count 2259269/18200000
output.27 Count 1179721/18200000
output.28 Count 603421/18200000
output.29 Count 305089/18200000
output.30 Count 153722/18200000
output.31 Count 77254/18200000
output.32 Count 38638/18200000
output.33 Count 19232/18200000
output.34 Count 9652/18200000
output.35 Count 4914/18200000
output.36 Count 2343/18200000
output.37 Count 1204/18200000
output.38 Count 637/18200000
output.39 Count 302/18200000
output.40 Count 152/18200000
output.41 Count 75/18200000
output.42 Count 52/18200000
output.43 Count 21/18200000
output.44 Count 13/18200000
output.45 Count 7/18200000
output.46 Count 1/18200000
output.47 Count 1/18200000
output.48 Count 1/18200000
output.49 Count 0/18200000
output.50 Count 0/18200000
output.51 Count 0/18200000
output.52 Count 0/18200000
output.53 Count 0/18200000
output.54 Count 0/18200000
output.55 Count 0/18200000
output.56 Count 0/18200000
output.57 Count 0/18200000
output.58 Count 0/18200000
output.59 Count 0/18200000
output.60 Count 0/18200000
output.61 Count 0/18200000
output.62 Count 0/18200000
output.63 Count 0/18200000
output.64 Count 0/18200000

输入时1820w随机数据,上述数据给出了CRCx情况下1820w输入产生的碰撞数量,可以看到在CRC32中出现了38638个冲突,在CRC49中才出现0碰撞,所以冲突率还是很高的。

 

posted @ 2021-04-26 16:46  juicejuice  阅读(405)  评论(0编辑  收藏  举报