什么是好的哈希函数?


130

什么是良好的哈希函数?在大学的数据结构课程中,我看到了很多哈希函数和应用程序,但是我大多数时候都知道要创建一个好的哈希函数非常困难。为了避免发生冲突,我的教授说:

function Hash(key)
  return key mod PrimeNumber
end

(mod是C和类似语言的%运算符)

质数应为哈希表的大小。我知道这是一个不错的功能,可以避免碰撞,而又可以避免快速碰撞,但是我该如何做得更好呢?对于数字键,字符串键是否有更好的哈希函数?


34
您是否考虑过使用以下一种或多种通用哈希函数:partow.net/programming/hashfunctions/index.html

在fnv_func中,p [i]的类型为char,第一次迭代后h会发生什么?是故意做的吗?

5
@martinatime说:Wikipedia en.wikipedia.org/wiki/Hash_function中有大量有关散列函数的信息,而本文的底部partow.net/programming/hashfunctions/index.html具有以多种语言实现的算法。
2501年

Answers:


33

对于基本上任何类型的数据都可以进行“普通”哈希表查找-Paul Hsieh的这是我用过的最好的数据。

http://www.azillionmonkeys.com/qed/hash.html

如果您关心加密安全性或其他更高级的内容,请使用YMMV。如果您只想在哈希表查找中使用踢屁股通用哈希函数,那么这就是您想要的。


感谢您的信息链接!我知道鲍勃·詹金斯(Bob Jenkins)和其他人所做的一些分析,这些分析都指向了相当不错的通用哈希函数,但是我还没有涉及到这一点。
康拉德·鲁道夫

我从詹金斯的网站阅读SFH是最好的,然后一个,但我认为杂音可能会做的更好,看到这样出色答卷:programmers.stackexchange.com/questions/49550/...
nawfal

2
YMMV代表什么?
cobarzan

3
@cobarzan您的里程可能会有所不同
ProgrammerDan

2
Hsieh的哈希函数很糟糕,冲突比我们想要的多一个数量级。特别是,仅后4个字节不同的字符串很容易发生冲突。如果您有30个字符串,在最后4个字节中有所不同,则在处理28个字节之后,哈希仅在最后2个字节中有所不同。这意味着您被保证会与其余两个字节值之一发生冲突。(是的,它很快。那又怎样。)
安德鲁·拉撒路

51

没有通用哈希的“好哈希函数”之类的东西(ed。是的,我知道有“通用哈希”之类的东西,但这不是我的意思)。取决于上下文,不同的标准确定哈希的质量。已经有两个人提到SHA。这是一个加密的哈希,对于哈希表(可能是您的意思)根本没有好处。

哈希表有非常不同的要求。但是,仍然很难普遍地找到一个好的哈希函数,因为不同的数据类型会公开不同的可以哈希的信息。根据经验,最好将一种类型的所有信息均等地考虑在内。这并不总是那么容易甚至不可能。出于统计的原因(并因此产生碰撞),在问题空间(即所有可能的对象)上产生良好的分布也很重要。这意味着,当对100到1050之间的数字进行哈希处理时,让最高有效位在哈希表中扮演重要角色是不好的,因为对于90%的对象,该数字将为0。让最后三个数字更重要数字确定哈希。

同样,在对字符串进行哈希处理时,考虑所有字符也很重要-除非事先知道所有字符串的前三个字符都相同,考虑这些则是浪费。

实际上,这是我建议阅读Knuth在《计算机编程艺术》第一卷中说的内容之一。3.另一本好书是朱丽安·沃克(Julienne Walker)的《散列的艺术》


1
Konrad,从理论上讲,您肯定是正确的,但是您是否曾经尝试使用我在评论中提到的Paul Hsieh哈希函数?对于许多不同类型的数据,这确实非常好!
克里斯·哈里斯

9

哈希函数有两个主要目的:

  • 将数据点均匀分散到n位。
  • 安全地识别输入数据。

不知道您要使用的哈希是不可能推荐哈希的。

如果您只是在程序中创建哈希表,则无需担心算法的可逆性或可破解性……SHA-1或AES对此完全不需要,因此最好使用FNV变体。FNV比您提到的简单质数模型具有更好的分散性(因此减少了冲突),并且更适应于各种输入大小。

如果您使用散列来隐藏和认证公共信息(例如对密码或文档进行哈希处理),则应使用由公众审查审查的主要哈希算法之一。哈希函数休息室是一个不错的起点。


哈希函数休息室的更新链接:larc.usp.br/~pbarreto/hflounge.html
Tim Partridge

与SHA1上的相同位数相比,FNV能够承受生日碰撞的程度如何?

@Kevin只要哈希的雪崩特性良好(输入中的微小变化=输出中的较大变化),那么生日冲突就只是哈希中位的函数。FNV-1a在这方面很出色,并且您可以根据需要在哈希中包含任意多或少的位(尽管要花一点力气才能得到不是2的幂的位数)。
Myrddin Emrys

5

这是一个很好的例子,也是为什么你永远不想写一个的例子。它是Fowler / Noll / Vo(FNV)哈希,它既是计算机科学的天才,又是纯巫毒的一部分:

unsigned fnv_hash_1a_32 ( void *key, int len ) {
    unsigned char *p = key;
    unsigned h = 0x811c9dc5;
    int i;

    for ( i = 0; i < len; i++ )
      h = ( h ^ p[i] ) * 0x01000193;

   return h;
}

unsigned long long fnv_hash_1a_64 ( void *key, int len ) {
    unsigned char *p = key;
    unsigned long long h = 0xcbf29ce484222325ULL;
    int i;

    for ( i = 0; i < len; i++ )
      h = ( h ^ p[i] ) * 0x100000001b3ULL;

   return h;
}

编辑:

  • Landon Curt Noll在其站点上建议使用FVN-1A算法,而不是原始FVN-1算法:改进的算法可以更好地分散哈希中的最后一个字节。我相应地调整了算法。

3
您可能希望在此站点上查找有关为什么选择这些值的一些信息:isthe.com/chongo/tech/comp/fnv/#fnv-prime
Cthutu 2010年

祝福你。这个简短,简单,高效,通用和有效的64位哈希函数正是我所需要的。
mattarod

3

我要说的主要经验法则是不要自己动手。尝试使用经过全面测试的产品,例如SHA-1或类似的产品。


他似乎不需要加密保护的任何东西,因此SHA-1可能会过大。
艾里克(Erik)2012年

顺便说一下,即使没有发现SHA-1的冲突,也要花数年或数月的时间才能找到。我建议使用SHA-256。
塞缪尔·艾伦

1

一个好的哈希函数具有以下属性:

  1. 在给定消息散列的情况下,攻击者在计算上无法找到另一条消息以使其散列相同,这在计算上是不可行的。

  2. 给定一对消息m'和m,找到两个使得h(m)= h(m')的消息在计算上是不可行的

两种情况一样。在第一种情况下,您正在尝试查找冲突的现有哈希值。在第二种情况下,您尝试查找任何两条冲突的消息。由于生日“悖论”,第二项任务要容易得多。

如果性能不是一个大问题,则应始终使用安全的哈希函数。通过强制哈希中的冲突可以执行非常聪明的攻击。如果您从一开始就使用强壮的东西,则可以确保自己免受这些伤害。

不要在新设计中使用MD5或SHA-1。包括我在内的大多数密码学家都会认为它们已损坏。这两种设计的弱点的主要根源在于,我上面概述的第二个属性不适用于这些结构。如果攻击者可以生成两条消息m和m',它们都散列为相同的值,则可以对您使用这些消息。SHA-1和MD5也遭受消息扩展攻击,如果您不小心,它们可能致命地削弱您的应用程序。

更现代的哈希(如Whirpool)是更好的选择。它不受这些消息扩展攻击的影响,并且使用与AES证明各种攻击的安全性相同的数学方法。

希望有帮助!


1
我认为在这种情况下,建议使用加密哈希函数是一个非常糟糕的建议。
斯拉瓦(Slava),2013年

@Slava:为什么?您说“在这种情况下,加密散列函数确实是一个糟糕的建议”的原因是什么?为什么这是个坏建议?这样做的相对缺点是什么?
让我思考一下

2
@Mowzer因为在哈希映射中使用的哈希函数应该快速且轻巧(假设它仍提供良好的哈希值),所以加密哈希显式地防止了暴力攻击在计算上是昂贵的。
斯拉瓦

1

您在这里所说的是要使用一种具有抗碰撞性的产品。尝试使用SHA-2。或尝试以一种单向压缩功能(从未尝试过)使用(好的)分组密码,例如宫口Preenel模式下的AES。问题在于您需要:

1)进行静脉输液。尝试使用Khinchin常数的小数部分的前256位或类似内容。2)有一个填充方案。简单。从MD5或SHA-3(Keccak [发音为'ket-chak'])之类的哈希中对其进行Barrow操作。如果您不关心安全性(其他一些人这样说),请查看Bob Jenkins的FNV或lookup2(实际上,我是第一个推荐lookup2的人)。还可以尝试MurmurHash,速度很快(请检查:.16 cpb) )。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.