为什么在Adler-32校验和算法中模数为65521?

时间:2009-05-29 17:52:15

标签: algorithm math checksum adler32

Adler-32校验和算法总和模数为65521.我知道65521是16位中最大的素数,但为什么在此算法中使用素数很重要?

(我确信一旦有人告诉我,答案就会显而易见,但我的大脑中的数论理论部分却无法正常工作。即使没有校验和算法的专业知识,一个聪明的人也会阅读http://en.wikipedia.org/wiki/Fletcher%27s_checksum可以解释一下。)

6 个答案:

答案 0 :(得分:19)

为什么mod prime用于Adler32?

来自Adler自己的网站http://zlib.net/zlib_tech.html

  

但是,Adler-32   已经建成,以尽量减少   如何对数据进行细微更改   导致相同的检查值,   通过显着使用总和   大于字节并使用   模数的素数(65521)。 是的   在这方面有一些分析   当之无愧,但它还没有   完成。

     

Adler-32的主要原因是   当然,软件的速度   的实施方式。

     

Adler-32的另一种选择是Fletcher-32,它将65521的模数替换为65535.本文表明Fletcher-32对于具有低速随机误码的信道是优越的。

使用它是因为素数往往具有更好的混合特性。究竟有多好还有待讨论。

其他说明

这个帖子中的其他人提出了一个有点令人信服的论点,即模数质量更适合检测比特交换。但是,这很可能不是,因为比特交换极为罕见。最常见的两个错误是:

  1. 任意位置的随机位翻转(1 - 0)。
  2. 网络中常见的比特移位(1 2 3 4 5 - > 2 3 4 5或1 1 2 3 4 5)
  3. 大多数位交换是由随机位翻转引起的,看起来有点像交换。

    纠错码实际上是为了承受n位偏差而设计的。来自阿德勒的网站:

      

    正确构造的CRC-n具有   不到n位的不错的属性   错误总是可以检测到的。这是   Adler-32并非总是如此 - 它可以   检测所有单字节或双字节错误但是   可能会错过一些三字节的错误。

    使用质数模数的有效性

    我在同一个问题上做了很长的写作。为什么模数素数?

    http://www.codexon.com/posts/hash-functions-the-modulo-prime-myth

    简短回答

    我们对素数的了解远远少于复合数。因此像Knuth这样的人开始使用它们。

    虽然素数与我们散列的大部分数据之间的关系可能较少,但增加表/模数也会降低碰撞的概率(有时甚至超过向下舍入到最接近的素数所获得的任何好处)。

    下面是每个桶的碰撞图,其中包含1000万个加密随机整数,比较mod 65521和65535。

答案 1 :(得分:4)

Adler-32算法是计算

A = 1 + b1 + b2 + b3 + ...

B = (1 + b1) + (1 + b1 + b2) + (1 + b1 + b2 + b3) + ... = 1 + b1 + 2 * b2 + 3 * b3 + ...

并以模数m报告它们。当m为素数时,模数的数字形成数学家称之为字段的数字。字段具有方便的属性,对于任何非零c,当且仅当c * a = c * b时,我们有a = b。将时间表modulo 6(不是素数)与时间表modulo 5进行比较,即:

* 0 1 2 3 4 5
0 0 0 0 0 0 0
1 0 1 2 3 4 5
2 0 2 4 0 2 4
3 0 3 0 3 0 3
4 0 4 2 0 4 2
5 0 5 4 3 2 1

* 0 1 2 3 4
0 0 0 0 0 0
1 0 1 2 3 4
2 0 2 4 1 3
3 0 3 1 4 2
4 0 4 3 2 1

现在,只要我们交换两个字节,A部分就会被愚弄 - 毕竟加法是可交换的。 B部分应该检测到这种错误,但是当m不是素数时,更多的位置是脆弱的。考虑一下

的Adler校验和模型6
1 3 2 0 0 4

我们有A = 4且B = 1.现在考虑交换b2和b4:

1 0 2 3 0 4

A和B未改变,因为2 * 3 = 4 * 0 = 2 * 0 = 4 * 3(模6)。也可以将2和5交换为相同的效果。当时间表不平衡时更有可能 - 模5,检测到这些变化。事实上,素数模数无法检测单个交换的唯一时间是交换两个相等的索引mod m(如果m很大,它们必须相距很远!)。^这个逻辑也可以应用于互换的子串。

使用较小模数的缺点是随机数据会稍微失败;然而,在现实世界中,腐败很少是随机的。

^证明:假设我们将索引i和j与值a和b交换。那么 i + b j = a j + b i,所以 i - a j + b j - b i = 0且(a-b)*(i-j)= 0.由于字段是一个整数域,因此a = b(值是全等)或i = j(索引是全等的)。< / p>

编辑:未知链接到的网站(http://www.zlib.net/zlib_tech.html)清楚地表明Adler-32的设计完全没有原则。由于DEFLATE流中的霍夫曼代码,即使很小的错误也可能改变成帧(因为它依赖于数据)并导致输出中的大错误。考虑这个答案是一个有点人为的例子,说明为什么人们将某些属性归为素数。

答案 2 :(得分:3)

长话短说:

素数的模数具有最佳的位移位属性,这正是我们想要的哈希值。

答案 3 :(得分:1)

对于完全随机的数据,桶越多越好。

假设数据在某种程度上是非随机的。现在,非随机性影响算法的唯一方法是创建一种情况,其中某些存储桶使用的概率高于其他存储桶。

如果模数是非素数,则影响构成模数的数字之一的任何模式都可能影响散列。因此,如果您使用15,则每3或5个模式以及每15个模式可能会导致冲突,而如果您使用13,则模式必须是每13个模式才会导致冲突。

65535 = 3 * 5 * 17 * 257,因此涉及3或5的模式可能会导致使用此模数的冲突 - 例如,如果由于某种原因,3的倍数更常见,那么只有多个桶是3将被充分利用。

现在我不确定这是否可能是一个问题。最好根据人们想要散列的类型的实际数据来确定碰撞率,而不是随机数。 (例如,涉及http://en.wikipedia.org/wiki/Benford's_law">Benford定律的数值数据或某些此类不规则会导致影响此算法的模式吗?如何将ASCII代码用于真实文本?)

答案 4 :(得分:0)

校验和通常用于检测两个不同的东西,特别是在两个东西不能在同一时间和地点同时出现的情况下。它们可能在不同的地方可用(例如,发送的信息包,而不是收到的信息包),或不同的时间(例如存储时的信息块,而不是回读时的信息块) 。在某些情况下,可能需要检查在两个不同位置独立存储的两件事是否可能匹配,而不必将实际数据从一个设备发送到另一个设备(例如,比较加载的代码图像或配置)。 / p>

如果被比较的东西不匹配的唯一原因是其中一个的随机损坏,那么使用Adler-32校验和的质数模数可能不是特别有用。但是,如果有可能其中一件事可能有某些“故意”的话。对其进行的更改,使用非素数模数可能会导致某些更改被忽视。例如,将字节从00更改为FF,以及将另一个字节更改为从FF到00之前或之后的257字节的某些倍数的效果将在使用Fletcher的校验和时取消,但是不是在使用Adler-32校验和时。这种情况不会特别可能发生在随机损坏中,但在更改程序时可能会发生这种抵消变化。它们特别可能不会出现相隔257个字节的精确倍数,但是通过使用质数模数(至少提供的数量)可以避免这种风险。文件中的字节小于模数

答案 5 :(得分:0)

答案在于场论。 操作加上和时间的集合Z / Z_n是当n是素数时的字段(即加法和与模n相乘)。

换句话说,以下等式:

m * x = (in Z/Z_n) 

对于m的任何值只有一个解(即x = 0)

考虑这个例子:

2 * x = 0 (mod 10)

这个等式有两个解,x = 0 AND x = 5.这是因为10不是素数,可以写为2 * 5.

此属性负责更好地分配哈希值。