了解循环多项式哈希冲突

时间:2013-05-03 18:38:30

标签: hash n-gram hash-collision

我有一个代码,它使用循环多项式滚动哈希(Buzhash)来计算n-gram源代码的哈希值。如果我使用小散列值(7-8位),则存在一些冲突,即不同的n-gram映射到相同的散列值。如果我将哈希值中的位增加到31,则有0次冲突 - 所有ngrams都映射到不同的哈希值。

我想知道为什么会这样?碰撞是否取决于文本中的n-gram数量或n-gram可以具有的不同字符数量,还是n-gram的大小?

如何在散列n-gram时使用滚动哈希值选择哈希值的位数?

2 个答案:

答案 0 :(得分:7)

长度如何影响碰撞

这只是一个排列问题。

  

如果我使用小哈希值(7-8位),则会发生一些冲突

好吧,让我们分析一下。对于8位,可以为任何给定输入生成2^8个可能的二进制序列。这是可以生成的256个可能的哈希值,这意味着理论上,生成的每个256消息摘要值都可以保证冲突。这被称为生日问题。

  

如果我将哈希值中的位增加到31,则会有0次冲突 - 所有ngrams都映射到不同的哈希值。

好吧,让我们应用相同的逻辑。凭借31位精度,我们有2^31种可能的组合。这是2147483648种可能的组合。我们可以将其概括为:

Let N denote the amount of bits we use.
Amount of different hash values we can generate (X) = 2^N

Assuming repetition of values is allowed (which it is in this case!)

这是一个指数增长,这就是为什么8位,你发现很多碰撞和31位,你发现很少碰撞。

这种影响如何碰撞?

嗯,只有非常少量的值,并且每个值映射到输入的机会相等,你就得到它:

Let A denote the number of different values already generated.
Chance of a collision is: A / X 

Where X is the possible number of outputs the hashing algorithm can generate.

X等于256时,您第一次碰撞时有1/256次碰撞的机会。然后,当生成不同的值时,您有2/256碰撞的机会。直到最终,您已生成255个不同的值,并且您有255/256碰撞的机会。下一次,显然它会成为256/256机会,或1,这是一个概率确定性。显然它通常不会达到这一点。碰撞可能比每256次循环发生的次数多得多。事实上,生日悖论告诉我们,在生成2^N/2消息摘要值之后,我们可以开始期待碰撞。因此,按照我们的示例,在我们创建16个唯一哈希之后。但是,我们确实知道必须每隔256个周期至少。哪个不好!

这意味着,在数学层面上,碰撞的可能性与可能的输出数量成反比,这就是为什么我们需要将消息摘要的大小增加到合理的长度。

关于散列算法的说明

碰撞是完全不可避免的。这是因为,存在极大数量的可能输入(2 ^所有可能的字符代码)和有限数量的可能输出(如上所示)。

答案 1 :(得分:1)

如果您的哈希值为8位,则可能的总值数为256 - 这意味着如果您散列257个不同的n-gram,肯定会发生至少一次碰撞(...很可能会得到更多的碰撞,即使少于257 n-gram) - 无论散列算法或散列数据如何,都会发生这种情况。

如果使用32位,则可能的总值大约为40亿 - 因此发生碰撞的可能性要小得多。

'如何选择位数':我猜这取决于哈希的使用。如果它用于将n-gram存储在某种散列数据结构(字典)中,那么它应该与数据结构的可能数量的“桶”相关 - 例如,如果字典少于256个桶,那么8位散列就可以了。

有关背景信息,请参阅this