一个32位哈希和两个16位哈希之间有碰撞率差异吗?

7
我正在处理一个可能会出现哈希碰撞问题的系统。基本上,该系统引用哈希表+树形结构中的项目。但是,所涉及的系统首先将包含结构路径的文本文件编译成包含散列值的二进制文件,以提高性能。然而,由于这个原因,碰撞非常严重,因为结构不能存储具有相同哈希值的2个项目;请求项目的部分将没有足够的信息来知道它需要哪一个。
我的初始想法是使用2个哈希,可以使用2个不同的算法或相同的算法两次,并使用2个盐来使其更加抗碰撞。对于不同哈希算法具有相同哈希的两个项目非常不可能。
我希望出于空间原因保持哈希值为32位,因此我认为可以使用两个16位算法而不是一个32位算法。但是,那样不会增加可能哈希值的范围...
我知道转换为两个32位哈希将更加抗碰撞,但我想知道转换为2个16位哈希是否比单个32位哈希至少有一些收益?我不是最擅长数学的人,所以我不知道如何开始检查答案,除了强制执行它...
关于系统的一些背景:
项目由人命名,它们不是随机字符串,通常由单词、字母和数字组成,没有空格。这是一个嵌套的哈希结构,所以如果你有像{a => {b => {c => 'blah'}}}这样的东西,你将通过获取a/b/c的值来获得'blah'的值,编译的请求将是3个哈希值在直接序列中,即a、b和c的哈希值。
只有在给定级别上出现碰撞时才会出现问题。顶层项目和较低级别之间的冲突是可以接受的。你可以有{a => {a => {...}}},几乎保证在不同级别上发生碰撞(不是问题)。
实际上,任何给定级别可能只有少于100个需要散列的值,并且在同一级别上不会重复。
为了测试我采用的哈希算法(忘记了哪一个,但我没有发明它),我下载了整个CPAN Perl模块列表,将所有名称空间/模块拆分为唯一单词,最后对每个单词进行哈希搜索冲突,我遇到了0个冲突。这意味着算法对CPAN名称空间列表中的每个唯一单词具有不同的哈希值(或者我做错了)。这对我来说足够好,但它仍然在我的脑海中挥之不去。
1个回答

9
如果您有两个产生不相关值的16位哈希,则刚刚编写了一个32位哈希算法。这将不会比任何其他32位哈希算法更好或更差。
如果您担心冲突,请确保使用良好的哈希算法对数据进行散列(有些仅是为了计算速度而编写,这不是您想要的),并增加哈希大小直到您感到舒适为止。
这引出了冲突概率的问题。事实证明,如果您的集合中有n个元素,则可能发生碰撞的n *(n-1)/ 2对元素。如果您使用k位哈希,则单个对碰撞的几率为2-k。如果您有很多东西,那么不同对之间发生碰撞的几率几乎是不相关的。这正是Poisson分布所描述的情况。
因此,您将看到的碰撞次数应该近似遵循泊松分布,其中λ = n * (n-1) * 2-k-1。从中可以得知无哈希冲突的概率约为e。在32位和100个项目的情况下,在一个级别中发生冲突的几率约为一百万分之1.1525。如果您进行足够多次的操作,并使用足够多不同的数据集,那么这些一百万分之一的机会最终会累加起来。
但请注意,您有许多正常大小的级别和少数大型级别,大型级别将对您的碰撞风险产生不成比例的影响。这是因为您向集合中添加的每个内容都可能与之前的任何内容发生冲突 - 内容越多,冲突风险越高。例如,具有1000个数据项的单个级别失败的几率约为1/10,000 - 这与具有100个数据项的100个级别的风险相当。
如果哈希算法不能正常工作,则您的碰撞风险将迅速上升。这种上升速度非常取决于故障的性质。

使用这些事实和您对应用程序使用情况的预测,您应该能够决定是否接受32位哈希的风险,或者是否应该升级到更大的哈希。


我会有些担心使用相同的16位哈希算法和2个不同的盐值;这两个哈希值隐式相关联。 - Ira Baxter
@IraBaxter 我说了盐,但我想我是错误的。我的意思是使用相同的算法,但第二次前缀一个值。该算法将字符串读入并迭代每个字符,每次更改哈希值,以使“ab”和“ba”具有不同的值。由于我不必担心相同字符串的冲突(哈希的目的),在第二次运行时给第二个项目添加前缀值应该足够使第一次运行后具有相同哈希的2个项目具有不同的哈希。(然而,我可能需要确认一下) - Exodist
1
@ira-baxter:如果哈希算法是具有密码学安全性的,那么就不应该存在这样的相关性。然而,这是一个不能被忽视的假设。 - btilly
1
@Exodist:我不是数学家,但如果你的两个哈希函数有算法关系,那么我会期望两个结果中的位相关。虽然这种相关性不容易被发现。老实说,考虑到构建32位哈希函数并不难,我不会冒险。 - Ira Baxter
@IraBaxter 我想我会妥协,我将使用我的32位哈希值,但编译阶段将花费时间计算第二个32位哈希值。当请求发出时,它将发送两倍的信息量,结构周围的代码将简单地忽略第二个哈希值,并且对于大多数项目永远不会计算它。然而,当发生冲突时,它将计算第二个哈希值以存储第二个项目,当请求针对这样的冲突对时,第二个哈希值将不被忽略。我可以通过让第二个哈希值按正确顺序跟随请求来优化这个过程。 - Exodist
如果不同种子哈希之间存在算法关系,那么这可能表明算法存在缺陷。良好的哈希函数应该没有不同种子之间的相关性。如果有的话,它就不是真正的带种子算法。SMHasher 在测试这方面做得很好。 - bryc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接