密码学 | 什么是散列算法?

前言

  • 在计算机科学中,散列算法的应用场景有很多,例如:散列表的散列函数、消息完整性验证的消息摘要算法,除此之外你还知道哪些应用场景呢?
  • 在这篇文章里,我将带你列举散列算法的基本要求 & 应用场景,希望能帮上忙。

系列文章

延伸文章

目录

1. 散列算法的性质

散列算法(Hash算法,又译哈希算法)是一种将任意长度输入转换为固定长度输出的算法,输出的结果就是散列值。通常来说,这种转换输出值域会远小于输入值域,也就是说,散列算法是压缩映射。例如,MD5的输出散列值为 128 位,SHA256的输出散列值为 256 位。

散列算法 示意图

散列算法有很多,但是都要满足以下性质 & 要求:

散列算法的性质

2. 什么是散列冲突?

前面提到,散列算法是压缩映射(输出值域远小于输入值域),因此肯定会存在两个甚至多个输入数据映射到同一个散列值的情况,这就是散列冲突(又称散列碰撞,Hash Collision)。注意,散列冲突是无法完全避免的,这其实只要用鸽巢原理(又称:抽屉原理)就很好理解了,假设有 10 个鸽巢,现有 11 只鸽子,无论分配多么平均,也肯定有一个鸽巢里有两只甚至多只鸽子。

举个例子,Java中的字符串"Aa""BB"的散列值就冲突了:

String str1 = "Aa";
String str2 = "BB";
System.out.println(str1.hashCode()); // 2112
System.out.println(str2.hashCode()); // 2112

2.1 如何降低散列冲突概率?

散列冲突虽然无法完全避免,但是可以设法降低散列冲突出现的概率:

  • 优化散列算法
    前面提到了散列算法的随机性:散列值在输出值域的分布尽量随机。这是为了避免出现“堆积”现象,即散列值集中于输出值域的某一块区域,这种情况无疑会增大冲突概率。

  • 扩大输出值域
    在输入值域相对稳定的情况下,扩大输出值域可以降低冲突概率。例如SHA的散列值长度就比MD5长,相应的冲突概率更低

2.2 如何解决散列冲突?

既然散列冲突完全避免,那么当出现散列冲突时,应该如何解决呢?在《数据结构 | 散列表是如何避免散列冲突的?》中,我们将讨论散列表中的解决方案。


3. 散列算法的应用场景

Editting...


4. 总结

  • 散列算法是一种将任意长度输入转换为固定长度输出的算法,由于是压缩映射,因而无法避免散列冲突。

参考资料

  • 《Java加密与解密的艺术》(第6、7、8、9章) —— 梁栋 著
  • 《数据结构与算法之美》(第21、22章) —— 王争 讲,极客时间 出品
  • 《散列算法》—— 维基百科

推荐阅读

感谢喜欢!你的点赞是对我最大的鼓励!欢迎关注彭旭锐的简书!