从生日悖论谈哈希碰撞
哈希映射压缩和冲突
简单来说哈希函数实现了各种长度和形式的输入经过公开的哈希函数的运算生成一个固定长度的串,并且这个过程是单向不可逆的
听起来确实很神奇且有用,像一个万能胶囊,在一个小的范围内装了很多不一样的东西,原来有10MB的文件或者1GB的文件经过哈希运算后都会被映射到一个固定长度的串,可见压缩程度之大。
但是又不得不思考另外一个问题:输入是无穷尽的,生成的哈希串长度是固定的,那么必然面临着多个不一样的输入被映射压缩为一个相同的哈希串,就是无限集合映射有限集合导致的哈希碰撞或者叫哈希冲突
如何解决?
无限输入集合向有限集合的压缩映射是必然会出现碰撞的,解决碰撞的一个有效方法是增加映射空间长度
生日悖论
前面讨论了哈希冲突的必然性,那么我们不禁要思考:那我该选择多少bit的哈希函数才能避免碰撞呢?
其实面对这个问题的时候,我最开始是这么想的:使用32bit的哈希函数这样还有42亿个空间呢,那么产生哈希碰撞岂不是42亿分之一,貌似可以高枕无忧了,先看一个有趣的问题:
x | p |
---|---|
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](https://pic2.zhimg.com/v2-5c0b68fa14163f008d1b98d6bd674af1_r.jpg)
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碰撞,所以冲突率还是很高的。