如果您有真正的随机、均匀分布的值,那么“切片”将产生完全相同的结果,就好像您从一开始就使用较小的值一样。要了解原因,请考虑这个非常简单的示例:假设您的随机生成器输出 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 位加密哈希函数会更好。