【问题标题】:Is there a collision rate difference between one 32-bit hash vs two 16 bit hashes?一个 32 位散列与两个 16 位散列之间是否存在冲突率差异?
【发布时间】:2011-07-30 12:26:53
【问题描述】:

我正在开发一个哈希冲突会成为问题的系统。本质上,有一个系统引用哈希表+树结构中的项目。然而,所讨论的系统首先将包含结构中路径的文本文件编译成包含散列值的二进制文件。这样做是出于性能原因。然而,由于这种冲突非常糟糕,因为该结构不能存储具有相同哈希值的 2 个项目;要求物品的部分没有足够的信息来知道它需要哪一个。

我最初的想法是,使用 2 种不同算法或两次使用相同算法的 2 次哈希,使用 2 种盐会更耐碰撞。对于不同的散列算法,两个项目具有相同散列的可能性很小。

出于空间原因,我希望将哈希值保持为 32 位,因此我想我可以改用两种 16 位算法而不是一种 32 位算法。但这不会增加可能的哈希值范围...

我知道切换到两个 32 位哈希会更耐冲突,但我想知道切换到两个 16 位哈希是否至少比单个 32 位哈希有一些好处?我不是最有数学倾向的人,所以我什至不知道如何开始检查答案,而不是强求它......

系统的一些背景:

物品由人类命名,它们不是随机字符串,通常由单词、字母和数字组成,没有空格。它是一个嵌套的哈希结构,所以如果你有类似 { a => { b => { c => 'blah' }}} 的东西,你将通过获取 a/b/c 的值来获得值 'blah',编译后的请求将是立即序列中的 3 个哈希值,a、b 和 c 的哈希值。

只有在给定级别发生碰撞时才会出现问题。顶层项目和较低层项目之间的冲突是正常的。你可以有 { a => {a => {...}}},几乎可以保证不同级别的碰撞(不是问题)。

在实践中,任何给定级别的哈希值都可能少于 100 个,并且在同一级别上没有一个是重复的。

为了测试我采用的散列算法(忘记是哪一个,但我没有发明它),我下载了 CPAN Perl 模块的整个列表,将所有命名空间/模块拆分为唯一的单词,最后对每一个进行散列搜索以查找冲突,我遇到了 0 次碰撞。这意味着该算法对 CPAN 命名空间列表中的每个唯一单词都有不同的哈希值(或者我做错了)。这对我来说似乎已经足够好了,但它仍然在我的脑海中挥之不去。

【问题讨论】:

    标签: hash 32-bit 16-bit collision


    【解决方案1】:

    如果您有 2 个 16 位散列,它们产生不相关的值,那么您刚刚编写了一个 32 位散列算法。这不会比任何其他 32 位哈希算法更好或更差。

    如果您担心冲突,请确保您使用的哈希算法可以很好地对您的数据进行哈希处理(有些只是为了计算速度快,这不是您想要的),并增加你的哈希大小直到你觉得舒服为止。

    这就提出了碰撞概率的问题。事实证明,如果您的收藏中有 n 事物,则可能会有 n * (n-1) / 2 对事物发生碰撞。如果您使用的是k 位哈希,则单对碰撞的几率为2<sup>-k</sup>。如果你有很多东西,那么不同对碰撞的几率几乎是不相关的。这正是Poisson distribution 描述的情况。

    因此,您将看到的碰撞次数应该大致遵循泊松分布,λ = n * (n-1) * 2<sup>-k-1</sup>。由此看来,没有哈希冲突的概率约为e<sup>-λ</sup>。使用 32 位和 100 个项目,在一个级别中发生碰撞的几率约为百万分之 1.1525。如果您这样做的次数足够多,并且有足够多不同的数据集,最终百万分之一的机会就会加起来。

    但请注意,您有许多正常大小的关卡和一些较大的关卡,较大的关卡会对您的碰撞风险产生不成比例的影响。那是因为你添加到集合中的每一个东西都可能与前面的任何东西发生碰撞——更多的东西等于更高的碰撞风险。因此,例如,具有 1000 个数据项的单个级别大约有 10,000 个失败的机会 - 这与具有 100 个数据项的 100 个级别的风险大致相同。

    如果散列算法不能正常工作,您的冲突风险将迅速上升。多快在很大程度上取决于故障的性质。

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

    【讨论】:

    • 我有点担心使用相同的 16 位哈希算法和 2 个不同的盐值;然后这两个哈希值是隐式相关的。
    • @IraBaxter 我说的是盐,但我认为我不正确。我的意思是使用相同的算法,但第二次前缀一个值。该算法将字符串插入并迭代每次更改的每个字符,以使“ab”和“ba”具有不同的值。而且由于我不必担心相同字符串(散列点)上的冲突,因此在第二次运行之前为值添加前缀应该足以让第一次运行后具有相同散列的 2 个项目在第二次运行中具有不同的散列. (然后我可能想再次确认)
    • @ira-baxter:如果哈希算法在密码学上是安全的,那么应该没有这种关联。然而,这是一个不应该被忽视的如果。
    • @Exodist:我不是数学家,但是如果您的两个哈希函数具有算法关系,那么我希望两个结果中的位是相关的。不是以容易看到的方式。坦率地说,考虑到构建 32 位哈希函数并不难,我不会冒险。
    • @IraBaxter 我想我会妥协,我会使用我的 32 位散列,但是编译阶段需要时间来计算第二个 32 位散列。当发出请求时,它将发送两倍的信息,结构周围的代码将简单地忽略第二个散列,并且对于大多数项目从不计算它。但是,当发生冲突时,它将计算第二个哈希以存储第二个项目,当请求进入这样一个冲突对时,第二个哈希将不会被忽略。我可以通过让第二个哈希都以正确的顺序跟踪请求来优化这一点。
    猜你喜欢
    • 2012-12-22
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 2010-10-29
    • 2018-09-13
    • 2017-12-02
    相关资源
    最近更新 更多