- 多项式:0x04C11DB7
- 字节序:大端
- 初始值:0xFFFFFFFF
- 反射:false
- XOR输出为:0L
- 测试流:0x0123、0x4567、0x89AB、0xCDEF 的结果为 CRC = 0x612793C3
计算CRC的代码(半字节、表驱动,我希望数据类型定义是自说明的):
uint32 crc32tab(uint16* data, uint32 len, uint32 crc)
{
uint8 nibble;
int i;
while(len--)
{
for(i = 3; i >= 0; i--)
{
nibble = (*data >> i*4) & 0x0F;
crc = ((crc << 4) | nibble) ^ tab[crc >> 28];
}
data++;
}
return crc;
}
需要的表格是(我认为短[16]表应该包含大[256]表中每隔16个元素的一个,但实际上这个表格包含前 16个元素,但这就是提供给我的方式):
static const uint32 tab[16]=
{
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
};
我修改了代码,使其不那么冗长,但功能保持不变。问题在于这个正向CRC计算看起来更像是反向的CRC计算。
我花了差不多一周的时间试图找出正确的多项式/算法/表格组合,但没有成功。如果有帮助的话,我想出了一个与上面的表驱动代码相对应的位算法,尽管这并不难。
uint32 crc32(uint16* data, uint32 len, uint32 crc)
{
uint32 i;
while(len--)
{
for(i = 0; i < 16; i++)
{
// #define POLY 0x04C11DB7
crc = (crc << 1) ^ (((crc ^ *data) & 0x80000000) ? POLY : 0);
}
crc ^= *data++;
}
return crc;
}
以下是预期结果 - 前两个16位字组成所需的未知CRC校验码,其余部分则是已知的数据本身(将这些示例提供给提供的算法进行计算,结果为0)。
{0x3288, 0xD244, 0xCDEF, 0x89AB, 0x4567, 0x0123}
{0xC704, 0xDD7B, 0x0000} - append as many zeros as you like, the result is the same
{0xCEBD, 0x1ADD, 0xFFFF}
{0x81AB, 0xB932, 0xFFFF, 0xFFFF}
{0x0857, 0x0465, 0x0000, 0x0123}
{0x1583, 0xD959, 0x0123}
^ ^
| |
unknown bytes that I need to calculate
我认为在0xFFFF或0x0000单词上进行测试很方便,因为计算方向和字节序不重要(希望如此:D)。因此,小心使用其他测试字节,因为计算方向相当狡猾:D。此外,您可以看到通过仅向算法提供零(向前和向后),结果是所谓的残留物(0xC704DD7B),这可能有所帮助。
所以...我写了至少10个不同的函数(按位、表格、多项式组合等)尝试解决这个问题,但没有成功。我在这里给出我寄予厚望的函数。它是上面那个基于表格的算法的“反向”算法,当然使用不同的表格。问题在于,我从中得到的唯一正确的CRC是所有0的消息,这并不意外。我还编写了按位算法的反向实现(反向移位等),但该算法仅正确返回第一个字节。
这是基于表格的算法,指针data应该指向消息的最后一个元素,输入crc应该是请求的crc(整个消息的0或者您可以采取另一种方法——消息的最后4个字节是您正在寻找的CRC:计算CRC初始值而不是将CRC附加到有效负载):
uint32 crc32tabrev(uint16* data, uint32 len, uint32 crc)
{
uint8 nibble;
int i;
while(len--)
{
for(i = 0; i < 4; i++)
{
nibble = (*data >> i*4) & 0x0F;
crc = (crc >> 4) ^ revtab[((crc ^ nibble) & 0x0F)];
}
data--;
}
return reverse(crc); //reverse() flips all bits around center (MSB <-> LSB ...)
}
这个表格,我希望它是“被选中的那个”。
static const uint32 revtab[16]=
{
0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC,
0x76DC4190, 0x6B6B51F4, 0x4DB26158, 0x5005713C,
0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C,
0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C
};
正文翻译:如你所见,这个算法有一些优点,使我陷入了困境。我觉得我可能正在正确的轨道上,但是我缺少某些东西。我希望多一个人的眼睛能看到我看不到的。对于长篇幅的帖子(没有土豆:D),我很抱歉,但我认为所有的解释都是必要的。提前感谢您的洞见或建议。
注:原文中出现了 "no potato",这里翻译成了“没有土豆”,但它并不影响原文的意思,仅仅是一个玩笑话。