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指令,所以只能在英特尔i7或更新的设备上运行。内部函数将正在运行的CRC哈希作为第一个参数,新数据作为第二个参数进行累加。返回值是新的运行CRC。
上述代码中0的初始运行CRC值非常关键。如果使用任何其他初始值,则CRC在实际意义上不是“可加性”的,因为您已经丢失了有关要分割的整数的信息。这正是您的示例中发生的情况。CRC函数从不将初始运行CRC值初始化为零,而通常为-1。原因是将CRC初始化为0允许任何数量的前导0在数据中简单地通过而不改变运行CRC值,其仍为0。因此,将CRC初始化为0在数学上是合理的,但在计算哈希的实际目的上,它是您最不想要的事情。
crc(A ^ B) = crc(A) ^ crc(B)
这个等式,因为谷歌上没有找到相关内容。 - HyperboreusCRC(A || B, iv) == CRC(B, CRC(A, iv))
,其中A
和B
是消息的两个部分,||
是相应的连接运算符,iv
是CRC计算的“初始化向量”,例如常见的0xffffffff
。这意味着,仅给出消息A
和消息B
的CRC值,就可以轻松地计算出CRC(A || B)
,而无需参考实际的消息A
。 - JimmyB