FNV'风味'和PHP实现

时间:2012-06-11 06:52:42

标签: php hash fnv

我正在尝试将FNV哈希算法集成到基于PHP的项目上,作为为各种数据(例如URL,关键字)生成哈希的要求的一部分。

我看到了Neven Boyanov的implementation。他提到由于PHP中的算术限制,他被迫使用按位移位和加法而不是乘法。他的实施是否正确?我的知识在某种程度上受限于计算机科学领域,因此我无法自己验证。

我的另一个问题是关于FNV的不同'风味'。我看到它提供了32位,64位和128位变体,但是使用上面的实现我总是得到8个字符的十六进制哈希(我使用dechex()将整数结果转换为十六进制)。

鉴于输入“Lorem ipsum dolor sit amet,consectetur adipiscing elit.Proin at libero mi,quis luctus massa。”,我得到以下十六进制结果:

  • (32位偏移)5b15c0f2
  • (64位偏移)6ea33cb5

为什么会这样?我期待64位FNV的16个字符的十六进制结果。 “风味”是指仅使用的算术运算种子和种子而不是结果的长度吗? (即如果我说64位FNV,散列函数将使用64位操作和种子,但结果仍然是32位)

非常感谢一点启示:)

2 个答案:

答案 0 :(得分:2)

我很久以前就编写了PHP FNV哈希函数,它是出于特定目的,所以当时32位实现就足够了。

回答第一个问题 - 通过比较算法(代码)和样本结果,对其他(C和C ++)实现进行了测试。因此,对于32位结果,它可以正常工作。

如果您想自己实现64位(或128位)版本,则应首先更改FNV_offset_basis,还应更改当前为第73行的表达式:

$hash += ($hash<<1) + ($hash<<4) + ($hash<<7) + ($hash<<8) + ($hash<<24);

...相当于乘以数字16777619(FNV_prime_32),二进制数为1000000000000000110010011 - 细分为此表达式:2^24 + 2^8 + 2^7 + 2^4 + 2^1 + 2^0

对于64位,您应该乘以1099511628211 - 二进制10000000000000000000000000000000110110011 ...表达式:2^88 + 2^8 + 2^7 + 2^5 + 2^4 + 2^1 + 2^0

我不知道PHP如何处理表达式$hash << 88,但你应该自己试验一下。在我的PHP 5.2.x上,它对于大于31的数字不起作用。

最后,您可能需要修改$hash = $hash & 0x0ffffffff;以从结果中删除一些垃圾。我通过实验想出来了。对于64位ot应该像$hash = $hash & 0x0ffffffffffffffff;。验证它是否与PHP一起正常工作。

您还可以使用其他PHP库来获得更高的算术精度。在我看来,使用按位移位更快。

实际上,您可以为任意位数生成FNV Hash。

答案 1 :(得分:0)

事实证明,我引用的implementation仅适用于32位FNV1。我设法编译FNV的C-source并使用二进制和Tom的建议tool来验证64位FNV确实返回16个字符的十六进制哈希值