20

我们正在尝试解决我们开发团队的内部争论:

我们正在寻找一个 64 位 PHP 哈希函数。我们找到了MurmurHash3 的PHP 实现,但 MurmurHash3 是 32 位或 128 位,而不是 64 位。

同事 #1 认为,要从 MurmurHash3 生成 64 位散列,我们可以简单地对 128 位散列的第一个(或最后一个,或任何一个)64 位进行切片,并且它将与本机一样防冲突64 位哈希函数。

同事 #2 认为我们必须找到一个原生 64 位散列函数来减少冲突,并且 128 位散列的 64 位切片不会像原生 64 位散列那样防冲突。

谁是正确的?

如果我们采用第一个(或最后一个,或任何一个)64 位加密散列(如 SHA1 而不是 Murmur3),答案是否会改变?

4

3 回答 3

19

如果您有真正的随机、均匀分布的值,那么“切片”将产生完全相同的结果,就好像您从一开始就使用较小的值一样。要了解原因,请考虑这个非常简单的示例:假设您的随机生成器输出 3 个随机位,但您只需要一个随机位即可使用。假设输出是

b1 b2 b3

可能的值为

000, 001, 010, 011, 100, 101, 110, 111

并且所有都以 1/8 的相同概率发生。现在,无论出于您的目的从这三个中切出什么位 - 第一个,第二个或第三个 - 无论位置如何,拥有“1”的概率始终是 1/2 - 对于“0”也是如此'。

您可以轻松地将这个实验扩展到 128 位中的 64 位情况:无论您切片哪些位,在某个位置以 1 或 0 结束的概率都是一半。这意味着如果您从均匀分布的随机变量中获取样本,那么切片不会或多或少地增加发生碰撞的可能性。

现在一个很好的问题是随机函数是否真的是我们能做的最好的防止碰撞的方法。但事实证明,只要函数偏离随机值,发现碰撞的概率就会增加。

加密哈希函数:同事 #1 获胜

现实生活中的问题是哈希函数根本不是随机的,相反,它们是无聊的确定性。但是密码散列函数的设计目标如下:如果我们不知道它们的初始状态,那么它们的输出将在计算上与真正的随机函数无法区分,即没有计算上有效的方法来区分散列输出之间的差异和真正的随机值。这就是为什么如果你能找到一个“鉴别器”,你会认为散列已经被破坏了,这是一种将散列与概率高于一半的真实随机值区分开来的方法。不幸的是,我们无法真正证明现有加密哈希的这些属性,但除非有人破解它们,否则我们可以假设这些属性具有一定的信心。关于说明该过程的 SHA-3 提交文件之一的区分符。

总而言之,除非为给定的加密哈希找到区分符,否则切片非常好,并且不会增加冲突的可能性。

非加密哈希函数:同事 #2 可能会获胜

非加密散列不必满足与加密散列相同的一组要求。它们通常被定义为非常快并且“在理智/仁慈的条件下”满足某些属性,但如果有人试图恶意操纵它们,它们可能很容易达不到要求。这在实践中意味着什么的一个很好的例子是今年早些时候提出的对哈希表实现 ( hashDoS ) 的计算复杂性攻击。在正常情况下,非加密哈希工作得非常好,但它们的抗碰撞性可能会被一些聪明的输入严重破坏。加密散列函数不会发生这种情况,因为它们的定义要求它们不受各种巧妙输入的影响。

因为有可能,有时甚至很容易,为非密码散列的输出找到像上面这样的区分符,我们可以立即说它们不符合密码散列函数的条件。能够分辨出差异意味着输出中的某个地方存在模式或偏差。

仅这一事实就意味着它们或多或少地偏离了随机函数,因此(根据我们上面所说的)碰撞可能比随机函数更有可能发生。最后,由于对于完整的 128 位已经发生冲突的概率较高,因此输出越短,这种情况就不会变得更好,在这种情况下,冲突的可能性可能更大。

tl; dr截断加密散列函数时,您是安全的。但是,与将具有较大输出的非加密哈希截断为 64 位相比,使用“本机”64 位加密哈希函数会更好。

于 2012-07-15T00:10:56.220 回答
7

由于雪崩效应,强散列是指源中的单个位变化导致散列的一半位平均翻转。那么,对于一个好的散列,“散列”是均匀分布的,因此每个部分或切片都受到相等且均匀分布的源比特数量的影响,因此与具有相同比特长度的任何其他切片一样强是。

只要哈希具有良好的属性和均匀分布,我就会同意同事 1。

于 2012-07-13T17:39:21.127 回答
2

如果没有提到这一点,这个问题似乎不完整:

对于特定类别的输入(例如,对于某些合理值的长度输入),一些散列可以证明是完美的散列。如果您截断该哈希,那么您可能会破坏该属性,在这种情况下,根据定义,您将冲突率从零增加到非零,并且您已经削弱了该用例中的哈希。nn

这不是一般情况,但它是截断哈希时合理关注的一个示例。

于 2013-06-25T22:20:52.147 回答