【发布时间】:2018-09-13 13:47:37
【问题描述】:
我见过几个问题,问“两个 16 位散列是否与 32 位散列具有相同的冲突率?”或“两个 32 位散列是否具有与 64 位散列相同的冲突率?”答案似乎是“是的,如果它们是不相关的体面散列函数”。但这意味着什么?
MurmurHash3 的作者这样说:
MurmurHash2_x86_64 并行计算两个 32 位结果并在最后混合它们,这速度很快,但意味着抗碰撞性仅与 32 位散列一样好。我建议避免使用这种变体。
他建议不要使用MurmurHash2_x86_64,但没有提到关于MurmurHash3_x86_128 的此类建议,它似乎将四个 32 位结果混合以产生128 位结果。
而且这个函数看起来更糟:如果消息小于 8 个字节,h3 和 h4 的输出总是会发生冲突。 h2 也容易发生冲突,100% 的时间会产生这样的结果:
任何长度小于 16 的空字节组合都会导致这些冲突,无论种子如何。
无论如何,如果 Appleby 所说的关于他的功能是真的,两个 32 位结果的抗碰撞性并不比单个 32 位结果好,为什么每次我强制碰撞一个结果,没有失败,其他不受影响?仅在一个哈希中的冲突呈指数级增长。
MurmurHash2_x86_64 中 h1 的碰撞... [2228688450、3117914388] !== [2228688450、2877485180] [957654412、3367924496] !== [957654412、762057742] [1904489323、1019367692] !== [1904489323、1894970953] [2752611220、3095555557] !== [2752611220、2609462765]我问这个的原因是因为我想在 JavaScript 中实现一个 64 位(或更高)的哈希来进行体面的错误检测。 32 位散列函数还不够好。 GitHub 上目前没有任何可用的解决方案足够快。由于 JavaScript 使用 32 位按位整数,因此只有在 uint32_t 上使用算术的函数在 JS 中是兼容的。许多 32 位函数似乎能够产生更大的输出而不会造成太多的性能损失。
我已经(在 JavaScript 中)实现了 MurmurHash2_x86_64 和 MurmurHash3_x86_128,它们的性能令人印象深刻。我还实现了MurmurHash2_160。
所有这些都具有与 32 位哈希相同的抗碰撞性吗?您如何判断结果是否足够相关以成为问题?我希望 64 位输出具有 64 位哈希的强度,160 位输出与 160 位哈希等一样强 - 同时在 32 位算术要求(JavaScript 限制)下。
更新:这是我的自定义 64 位哈希,专为速度而设计(比我在 Chrome/Firefox 下优化的 32 位 MurmurHash3 更快)。
function cyb_beta3(key, seed = 0) {
var m1 = 1540483507, m2 = 3432918353, m3 = 433494437, m4 = 370248451;
var h1 = seed ^ Math.imul(key.length, m3) + 1;
var h2 = seed ^ Math.imul(key.length, m1) + 1;
for (var k, i = 0, chunk = -4 & key.length; i < chunk; i += 4) {
k = key[i+3] << 24 | key[i+2] << 16 | key[i+1] << 8 | key[i];
k ^= k >>> 24;
h1 = Math.imul(h1, m1) ^ k; h1 ^= h2;
h2 = Math.imul(h2, m3) ^ k; h2 ^= h1;
}
switch (3 & key.length) {
case 3: h1 ^= key[i+2] << 16, h2 ^= key[i+2] << 16;
case 2: h1 ^= key[i+1] << 8, h2 ^= key[i+1] << 8;
case 1: h1 ^= key[i], h2 ^= key[i];
h1 = Math.imul(h1, m2), h2 = Math.imul(h2, m4);
}
h1 ^= h2 >>> 18, h1 = Math.imul(h1, m2), h1 ^= h2 >>> 22;
h2 ^= h1 >>> 15, h2 = Math.imul(h2, m3), h2 ^= h1 >>> 19;
return [h1 >>> 0, h2 >>> 0];
}
它基于 MurmurHash2。每个内部状态h1、h2 分别初始化,但与相同的密钥块混合。然后它们与备用状态(例如h1 ^= h2)混合。作为最终确定的一部分,它们在最后再次混合。
有什么可以表明这比真正的 64 位散列更弱吗?它正确地通过了我自己的基本雪崩/碰撞测试,但我不是专家。
【问题讨论】:
标签: javascript hash probability hash-collision murmurhash