Hash 函数的现状,2012

转自:http://blog.csdn.net/porui/article/details/11907389

看到一篇介绍hash的文章不错,所以翻译了一下。原文:

http://blog.reverberate.org/2012/01/state-of-hash-functions-2012.html

经典的非加密hash函数在最近几年取得了迅速的发展,最近搜索相关信息,高兴的发现又有前沿的hash函数发布了,虽然离上一次看到新hash函数的时间才半年或一年。

非加密hash函数以一个字符串为输入,计算出一个整数作为输出。Hash函数的一个喜人地方是,输出的整数均匀的分布在输出域空间里,即使是对于相似的输入。与加密hash函数不同,非加密hash函数并不要求能抵挡利用碰撞进行的hacker攻击。加密hash函数则有这方面的要求(抵抗碰撞),但是碰撞速率非常慢:SHA-1大约是0.09 bytes/cycle,而最新的非加密hash函数的碰撞率大约为3bytes/cycle。所以在抵御攻击的能力上,破解非加密hash比加密hash大约快33倍。所以非加密hash主要还是用作hash表。

作为有趣的一点,Lua社区目前有一个争论:如果可以的话,当Lua的 hash函数被攻击使得它的hash table 的实现被迫进入O(n)复杂度的最差性能时,该怎么办。例如攻击者不断的传数据给Lua,而Lua则把这些数据放到Lua的hash table里,这样就达到了Dos攻击的目的。Lua的作者有些怀疑这种攻击的现实性(这种Dos攻击是否会比其它的Dos攻击代价小),不过不管怎样他还是计划在hash函数启动时加入随机种子。对于加密hash函数,这也是一种令人感兴趣的可选的增加碰撞难度的方法,但代价是输出不可重现。

既然有那么多的hash函数可选,并且数量还在不断增加,那么我想有必要总结一下我在这方面所知道的那些东西了。

Bob Jenkins’s Functions

Bob Jenkins 致力于hash 函数大约有15年左右了。1997年他在Dr. Dobbs 的期刊上发表了一篇关于hash函数的文章:A hash function for hash Table lookup现在网上依然能找到这篇文章,虽然内容在原文的基础上增加了不少。在这篇文章中,Bob广泛的归类了已存的hash函数,并提出了自己的”lookup2”。随后他又在2006年发布了lookup3 ,对于本文来说,我将认为这是第一个“现代”的hash函数。从某种意义上来说它不仅快速(0.5bytyes/cycle according to Bob)而且没有任何严重缺陷。

关于Bob的函数的更多信息可以在Wikipedia上找到:Jenkins hash function.

第二代:MurmurHash

2008年Austin Appleby 发表了一个新的称作“MurmurHash”的hash 函数。在它最近的版本中其hash速度大约是lookup3的2倍(大约1byte/cycle),并且同时有32-bit和64-bit两个版本。32-bit版的只使用32-bit公式并输出32-bit的hash,64-bit版的使用64-bit公式产出64-bit的hash。跟据Austin的分析该函数拥有优秀的特性,然而Bob Jenkins在DR.Dobbs上发表的扩充文章说:我能看到[MurmurHash]比我的lookup3差,但是我不知道差多少,我没有测试。由于优秀的速度和统计特性,MurmurHash很快就变的流行起来。

第三代:CityHash and SpookyHash

2011年2个基于MurmurHash的改进函数发表,这两个函数都是在指令级别的并行性上对MurmurHash进行了加强。Google发布了CityHash(written by Geoff Pike and Jyrki Alakuijala)Bob Jenkins 发布了自己的SpookyHash(之所以这样命令是因为在万圣节前夕发布的)。两个函数都是原MurmurHash速度的2x,但两个函数都使用了64-bit的公式,而没有32-bit的版本。CityHash依赖于CRC32指令集,该指令出现在SSE 4.2(Intel Nehalem及以后)。SpookyHash产生128位的输出,而CityHash有64-bit,128-bit和256-bit可选

哪个函数最好/最快

就我看来,本文中所谈到的所有hash函数在统计特性上都是足够好的。有一个方面要注意,CityHash/SpookyHash产生大于64-bit的输出,不过对于32-bit的hash 函数已经有很多了(足够了)。另外一些应用可能需要使用128或256位的hash

如果你正打算用32-bit的hash,显然MurmurHash看起来是优胜者,因为它是仅有的比lookup3快速而又原生支持32-bit的hash。32位的机器也可以编译并执行City和Spooky,但我估计它会比较慢因为要模拟64-bit的公式

在64位的机器上没有进一步的benchmarking的前提下很难说哪一个更好。我个人更倾向于Spooky而不是City,因为后者依赖于CRC32指令集进行加速,而CRC32并不是哪里都可用的

另外一个因素是对齐和非对齐访问。MurmurHash(不像City或Spooky)有一个变体,该变体只实施对齐读,因为在很多架构上进行非对齐读会导致crash或者返回错误的数据(非对齐读在C上是没有定义的)。City和Spooky两者都解决了这个问题,通过使用memcpy()复制输入数据到对齐的存储器。Spooky 一次复制一个块(如果ALLOW_UNALIGNED_READS没有定义);City则一次复制一个整数。在支持处理非对齐读的机器上(像x86和x86-64)memecp将被优化掉。但我在我的小RAM盒子上测试了一下,发现:

 
 
 C++ |   copy code |? 
01
#include <stdint.h>
02
 
03
#include <string.h>
04
 
05
int32_t read32_unaligned(const void *buf) {
06
 
07
&nbsp;&nbsp;int32_t ret;
08
 
09
&nbsp;&nbsp;memcpy(&ret, buf, 4);
10
 
11
&nbsp;&nbsp;return ret;
12
 
13
}

编译这段非常低效的代码(在x86上的单指令集):

       
       
 ABAP |   copy code |? 
01
0: b500       push {lr}
02
2: 2204       movs r2, #4
03
4: b083       sub sp, #12
04
6: 4601       mov r1, r0
05
8: eb0d 0002  ADD.w r0, sp, r2
06
c: f7ff fffe  bl 0 
07
10: 9801       ldr r0, [sp, #4]
08
12: b003       ADD sp, #12
09
14: bd00       pop {pc}
10

总结,MurmurHash 依然是最好的选择,如果你需要32-bit hash或机器只支持对齐读。CityHash和SpookyHash似乎在x86-64上会更快点,但我总是认为他们是特定于这种架构的,因为我还不知道有其它架构既是64-bit又允许非对齐读的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值