问题 CRC32添加剂?


在几个地方我读过crc32是加法的,因此:CRC(A xor B)= CRC(A)xor CRC(B)。

我写的以下代码证实了上述陈述:

import zlib
def crc32(data):
        return zlib.crc32(data) & 0xffffffff

print crc32(chr(ord("A") ^ ord("B")))
print crc32("A") ^ crc32("B")

节目输出:

1259060791
2567524794

有人能提供一个证明这个理论的正确代码,还是指出我失败的地方?


6059
2017-08-08 06:16


起源

我最初误读了 - 我想,好吧,我确实使用CRC32很多,但我可以随时退出......我真的可以...... - Joe Enos
你能给出一些说明这一点的消息来源吗? crc(A ^ B) = crc(A) ^ crc(B) 谷歌让我失望。 - Hyperboreus
您是否通过证明该假设失败来回答您自己的问题? - Jordan
CRC在消息串联方面是“附加的”: CRC(A || B, iv) == CRC(B, CRC(A, iv)) 哪里 A 和 B 是消息的两部分, || 是一个相应的连接运算符,和 iv 是用于CRC计算的'初始化矢量',例如,共同的 0xffffffff。这意味着,仅给出消息的CRC值 A 和消息 B, CRC(A || B) 可以通过简单计算而无需参考实际消息 A。 - JimmyB


答案:


CRC在数学意义上是加性的,因为CRC散列只是来自所有数据(被视为一个巨整数)的无进位除法除以多项式常数的余数值。使用您的示例,它类似于这种事情:

7 mod 5 = 2

6 mod 5 = 1

(7 mod 5)+(6 mod 5)= 3

(7 + 6)mod 5 = 3

在这个类比中,'5'是我们的CRC多项式。

这是一个使用的示例(基于gcc):

#include <stdio.h>
#include <x86intrin.h>

int main(void)
{
        unsigned int crc_a = __builtin_ia32_crc32si( 0, 5);
        printf( "crc(5) = %08X\n", crc_a );
        unsigned int crc_b = __builtin_ia32_crc32si( 0, 7);
        printf( "crc(7) = %08X\n", crc_b );
        unsigned int crc_xor = crc_a ^ crc_b;
        printf( "crc(5) XOR crc(7) = %08X\n", crc_xor );
        unsigned int crc_xor2 = __builtin_ia32_crc32si( 0, 5 ^ 7);
        printf( "crc(5 XOR 7) = %08X\n", crc_xor2 );

        return 0;
}

输出符合预期:

plxc15034> gcc -mcrc32 -Wall -O3 crctest.c
plxc15034> ./a.out
crc(5) = A6679B4B
crc(7) = 1900B8CA
crc(5) XOR crc(7) = BF672381
crc(5 XOR 7) = BF672381

由于此代码使用x86 CRC32指令,因此它只能在Intel i7或更高版本上运行。内部函数将运行的CRC哈希作为第一个参数,将新数据作为第二个参数进行累积。返回值是新运行的CRC。

上面代码中初始运行的CRC值为0是至关重要的。使用任何其他初始值,然后CRC在实际意义上不是“加性的”,因为您已经有效地丢弃了有关您要分割的整数的信息。这正是你的例子中正在发生的事情。 CRC函数永远不会将初始运行的CRC值初始化为零,但通常为-1。原因是初始CRC为0允许数据中任意数量的前导0简单地通过而不改变运行的CRC值,该值保持为0.因此,将CRC初始化为0在数学上是合理的,但是出于计算的实际目的哈希,这是你想要的最后一件事。


6
2017-08-09 04:47





CRC-32算法基于多项式除法,并添加了一些额外的步骤。纯多项式余数是加性的。

由此,我的意思是:mod(poly1 + poly2,poly3)= mod(mod(poly1,poly3)+ mod(poly2,poly3),poly3)

CRC-32算法建立在此基础之上,并且是非加性的。要计算字节数组m的CRC-32:

  1. 通过0xFFFFFFFF将前4个字节进行异或。
  2. 将较早的字节视为较高的多项式幂,并将较低阶的位视为较高的多项式幂。例如,字节0x01 0x04将是多项式x ^ 15 + x ^ 3。
  3. 将多项式乘以x ^ 32。
  4. 取此多项式的余数除以CRC-32多项式0x104C11DB7。余数多项式的度数<32。
  5. 将较低的功率视为较高阶位。例如,多项式x ^ 2将是32位整数0x40000000。
  6. XOR结果为0xFFFFFFFF。

纯多项式余数运算在步骤#4中。步骤#1和#6使CRC-32算法不加。因此,如果撤消步骤#1和#6的效果,则可以将CRC-32算法修改为加法。

(也可以看看: Python CRC-32问题


2
2017-08-10 04:09





如果a,b和c具有相同的长度,则CRC(a)xor CRC(b)xor CRC(c)等于CRC(x或b x或c)。回到原始配方,这意味着CRC(a xor b)等于CRC(a)xor CRC(b)xor CRC(z),其中z是与其他两个序列长度相同的零序列。


2
2018-02-23 23:59



我可以证实这一点 CRC(A ⊕ B) = CRC(A) ⊕ CRC(B) 不是真的,但是 CRC(A ⊕ B ⊕ C) = CRC(A) ⊕ CRC(B) ⊕ CRC(C)因此 CRC(A ⊕ B ⊕ C ⊕ D ⊕ E) = CRC(A) ⊕ CRC(B) ⊕ CRC(C) ⊕ CRC(D) ⊕ CRC(E) (如果你改变了 C 至 C ⊕ D ⊕ E)。有没有理由为什么它适用于奇数个操作数,而不是偶数? - Victor
如果CRC32使用了0x00000000的初始化向量,那么 CRC(A ⊕ B) = CRC(A) ⊕ CRC(B) 会持有,但它对前导零不敏感。 CRC通常使用0xFFFFFFFF的初始化向量(使其表现为序列的零初始化CRC,其前四个字节与FF进行异或)。如果将CRCZ定义为使用零初始化向量执行的CRC,则 CRC(X) = CRCZ(x ⊕ FFFFFFFF00..),和 CRC(X ⊕ Y) = CRCZ(x ⊕ y ⊕ FFFFFFFF00...)。两元素表达 CRC(X) ⊕ CRC(Y)... - supercat
......相当于 CRCZ(x ⊕ FFFFFFFF00...) ⊕ CRCZ(y ⊕ FFFFFFFF00...),这相当于 CRCZ(x ⊕ Y ⊕ FFFFFFFF00... ⊕ FFFFFFFF00...) 因此 CRCZ(x ⊕ Y) [这不等于 CRCZ(x ⊕ Y ⊕ FFFFFFFF00...) 因此不等于 CRC(x ⊕ Y)]。对于算术类比,定义f(x)= - x,并使用乘法而不是xor。那么f(x·y·z)= - (x·y·z)=( - x)( - y)( - z)= f(x)·f(y)·f(z),但f( x·y)= - (x·y)= - (( - x)·( - y))= - (f(x)·f(y))。 - supercat


这意味着CRC结果的每个位位置仅由输入中的等效位位置驱动。考虑一下B == 0的例子。

对于某些原始xor或加性校验和算法,您所描述的关系更可能是正确的。


1
2017-08-08 07:39