基本 CRC32 Wikipedia 实现不同于在线看到的标准 CRC32

Posted

技术标签:

【中文标题】基本 CRC32 Wikipedia 实现不同于在线看到的标准 CRC32【英文标题】:Basic CRC32 Wikipedia implementation differs from standard CRC32 seen online 【发布时间】:2015-06-27 00:46:18 【问题描述】:

我有一个基本的 CRC32 实现,遵循***的 Code Fragment:1 sample。我认为我做得对,修改为使用 n 位寄存器作为剩余多项式,而不是按照示例使用 n+1 位。

我得到的结果与网上的CRC32实现结果不同。在我的实施中,我必须在此处进行哪些更改?

请忽略 Console.Writeline 的逻辑语句。

    const UInt32 poly = 0x04C11DB7;

    public static UInt32 GenerateCRC_32(byte[] message)
    
        byte[] augmentedMsg = new byte[message.Length + 4];
        message.CopyTo(augmentedMsg, 0);

        UInt32 remainder = Convert.ToUInt32(augmentedMsg[0]) << 24 |
                           Convert.ToUInt32(augmentedMsg[1]) << 16 |
                           Convert.ToUInt32(augmentedMsg[2]) <<  8 |
                           Convert.ToUInt32(augmentedMsg[3]);

        for (Int32 i = 4; i < augmentedMsg.Length; i++)
        
            for (int bit = 0; bit < 8; bit++)
            
                UInt32 nextBit = ((UInt32)augmentedMsg[i] >> (7 - bit)) & 0x01;
                if ((remainder & 0x80000000) > 0)
                
                    Console.WriteLine("---------------DO XOR --------------------");
                    Console.WriteLine(Convert.ToString(((remainder << 1) | nextBit), 2).PadLeft(32, '0'));
                    Console.WriteLine(Convert.ToString(poly, 2).PadLeft(32, '0'));
                    Console.WriteLine("------------------------------------------");

                    remainder = ((remainder << 1) | nextBit) ^ poly;

                    Console.WriteLine(Convert.ToString(remainder, 2).PadLeft(32, '0'));
                    Console.WriteLine("------------------------------------------");
                
                else
                
                    remainder = (remainder << 1) | nextBit;

                    Console.WriteLine("--------------NO---------------------");
                    Console.WriteLine(Convert.ToString(remainder, 2).PadLeft(32, '0'));
                    Console.WriteLine("------------------------------------------");
                
            
        

        Console.WriteLine(Convert.ToString(remainder, 2).PadLeft(32, '0'));
        Console.WriteLine(remainder.ToString("X"));

        return remainder;
    

我不是在寻找优化逻辑的最佳方法,因为我只是想使用 C# 来遵循 Wikipedia 示例。

输入消息:'A'(十六进制:0x41) 输出:0x30476DC0 根据this website:输出应为:0xD3D99E8B

我认为我缺少 CRC 的反转/初始化,但我不确定如何更改此基本实现以获得与网站结果等效的结果。

运行我的程序时的输出:

--------------NO---------------------
10000010000000000000000000000000
------------------------------------------
---------------DO XOR --------------------
00000100000000000000000000000000
00000100110000010001110110110111
------------------------------------------
00000000110000010001110110110111
------------------------------------------
--------------NO---------------------
00000001100000100011101101101110
------------------------------------------
--------------NO---------------------
00000011000001000111011011011100
------------------------------------------
--------------NO---------------------
00000110000010001110110110111000
------------------------------------------
--------------NO---------------------
00001100000100011101101101110000
------------------------------------------
--------------NO---------------------
00011000001000111011011011100000
------------------------------------------
--------------NO---------------------
00110000010001110110110111000000
------------------------------------------
00110000010001110110110111000000

最后一行转成十六进制:0x30476DC0

@Mark Adler 的后续评论:**

我对上面的修改如下,修改如下(cmets被内联添加到代码中):

    初始化为 0xFFFFFFFF 反转输入消息字节

    异或到最终值,异或值的反转

    public static UInt32 GenerateCRC_32(byte[] message) byte[] augmentedMsg = new byte[message.Length + 8]; message.CopyTo(augmentedMsg, 4); // 修改为初始化创建空间

    UInt32 remainder = Convert.ToUInt32(augmentedMsg[0]) << 24 |
                       Convert.ToUInt32(augmentedMsg[1]) << 16 |
                       Convert.ToUInt32(augmentedMsg[2]) <<  8 |
                       Convert.ToUInt32(augmentedMsg[3]);
    
    remainder = ~remainder; // Overwrite the above and initialized the register to 0xFFFFFFFF
    
    for (Int32 i = 4; i < augmentedMsg.Length; i++)
    
        byte reversedMessage = Reverse(augmentedMsg[i]); // Reversed the augmented message byte
        for (int bit = 0; bit < 8; bit++)
        
            UInt32 nextBit = Convert.ToUInt32(reversedMessage >> (7 - bit)) & 0x1; // Use the reversed message byte
            if ((remainder & 0x80000000) > 0)
            
                Console.WriteLine("---------------DO XOR --------------------");
                Console.WriteLine(Convert.ToString(((remainder << 1) | nextBit), 2).PadLeft(32, '0'));
                Console.WriteLine(Convert.ToString(poly32, 2).PadLeft(32, '0'));
                Console.WriteLine("------------------------------------------");
    
                remainder = Convert.ToUInt32((UInt32)((UInt32)(remainder << 1) | nextBit) ^ poly32);
    
                Console.WriteLine(Convert.ToString(remainder, 2).PadLeft(32, '0'));
                Console.WriteLine("------------------------------------------");
            
            else
            
                remainder = (UInt32)((UInt32)(remainder << 1) | nextBit);
    
                Console.WriteLine("--------------NO---------------------");
                Console.WriteLine(Convert.ToString(remainder, 2).PadLeft(32, '0'));
                Console.WriteLine("------------------------------------------");
            
        
    
    
    Console.WriteLine(Convert.ToString(remainder, 2).PadLeft(32, '0') + "(" + remainder.ToString("X") + ")");
    
    remainder = (~remainder);
    
    Console.WriteLine("XOR ^ 0xFFFFFFFF : " + Convert.ToString(remainder, 2).PadLeft(32, '0') + "(" + remainder.ToString("X") + ")");
    
    remainder = Reverse(remainder);
    
    Console.WriteLine("Reversed the Abv : " + Convert.ToString(remainder, 2).PadLeft(32, '0') + "(" + remainder.ToString("X") + ")");
    return remainder;
    

输出:

---------------DO XOR --------------------
11111111111111111111111111111111
00000100110000010001110110110111
------------------------------------------
11111011001111101110001001001000
------------------------------------------
---------------DO XOR --------------------
11110110011111011100010010010000
00000100110000010001110110110111
------------------------------------------
11110010101111001101100100100111
------------------------------------------
---------------DO XOR --------------------
11100101011110011011001001001110
00000100110000010001110110110111
------------------------------------------
11100001101110001010111111111001
------------------------------------------
---------------DO XOR --------------------
11000011011100010101111111110010
00000100110000010001110110110111
------------------------------------------
11000111101100000100001001000101
------------------------------------------
---------------DO XOR --------------------
10001111011000001000010010001010
00000100110000010001110110110111
------------------------------------------
10001011101000011001100100111101
------------------------------------------
---------------DO XOR --------------------
00010111010000110011001001111010
00000100110000010001110110110111
------------------------------------------
00010011100000100010111111001101
------------------------------------------
--------------NO---------------------
00100111000001000101111110011011
------------------------------------------
--------------NO---------------------
01001110000010001011111100110110
------------------------------------------
--------------NO---------------------
10011100000100010111111001101100
------------------------------------------
---------------DO XOR --------------------
00111000001000101111110011011000
00000100110000010001110110110111
------------------------------------------
00111100111000111110000101101111
------------------------------------------
--------------NO---------------------
01111001110001111100001011011110
------------------------------------------
--------------NO---------------------
11110011100011111000010110111100
------------------------------------------
---------------DO XOR --------------------
11100111000111110000101101111000
00000100110000010001110110110111
------------------------------------------
11100011110111100001011011001111
------------------------------------------
---------------DO XOR --------------------
11000111101111000010110110011110
00000100110000010001110110110111
------------------------------------------
11000011011111010011000000101001
------------------------------------------
---------------DO XOR --------------------
10000110111110100110000001010010
00000100110000010001110110110111
------------------------------------------
10000010001110110111110111100101
------------------------------------------
---------------DO XOR --------------------
00000100011101101111101111001010
00000100110000010001110110110111
------------------------------------------
00000000101101111110011001111101
------------------------------------------
--------------NO---------------------
00000001011011111100110011111010
------------------------------------------
--------------NO---------------------
00000010110111111001100111110100
------------------------------------------
--------------NO---------------------
00000101101111110011001111101000
------------------------------------------
--------------NO---------------------
00001011011111100110011111010000
------------------------------------------
--------------NO---------------------
00010110111111001100111110100000
------------------------------------------
--------------NO---------------------
00101101111110011001111101000000
------------------------------------------
--------------NO---------------------
01011011111100110011111010000000
------------------------------------------
--------------NO---------------------
10110111111001100111110100000000
------------------------------------------
---------------DO XOR --------------------
01101111110011001111101000000000
00000100110000010001110110110111
------------------------------------------
01101011000011011110011110110111
------------------------------------------
--------------NO---------------------
11010110000110111100111101101110
------------------------------------------
---------------DO XOR --------------------
10101100001101111001111011011100
00000100110000010001110110110111
------------------------------------------
10101000111101101000001101101011
------------------------------------------
---------------DO XOR --------------------
01010001111011010000011011010110
00000100110000010001110110110111
------------------------------------------
01010101001011000001101101100001
------------------------------------------
--------------NO---------------------
10101010010110000011011011000010
------------------------------------------
---------------DO XOR --------------------
01010100101100000110110110000100
00000100110000010001110110110111
------------------------------------------
01010000011100010111000000110011
------------------------------------------
--------------NO---------------------
10100000111000101110000001100110
------------------------------------------
---------------DO XOR --------------------
01000001110001011100000011001100
00000100110000010001110110110111
------------------------------------------
01000101000001001101110101111011
------------------------------------------
--------------NO---------------------
10001010000010011011101011110110
------------------------------------------
---------------DO XOR --------------------
00010100000100110111010111101100
00000100110000010001110110110111
------------------------------------------
00010000110100100110100001011011
------------------------------------------
--------------NO---------------------
00100001101001001101000010110110
------------------------------------------
--------------NO---------------------
01000011010010011010000101101100
------------------------------------------
--------------NO---------------------
10000110100100110100001011011000
------------------------------------------
---------------DO XOR --------------------
00001101001001101000010110110000
00000100110000010001110110110111
------------------------------------------
00001001111001111001100000000111
------------------------------------------
--------------NO---------------------
00010011110011110011000000001110
------------------------------------------
--------------NO---------------------
00100111100111100110000000011100
------------------------------------------
00100111100111100110000000011100(279E601C)
XOR ^ 0xFFFFFFFF : 11011000011000011001111111100011(D8619FE3)
Reversed the Abv : 11000111111110011000011000011011(C7F9861B)

这不是预期的输出。我使用下表查找代码实现了相同的结果,结果与上面完全相同(0xC7F9861B),这是错误的

public static UInt32 GenerateCRC_32_from_Table(byte[] message)
    
        byte[] augmentedMsg = new byte[message.Length + 4];
        message.CopyTo(augmentedMsg, 0);

        UInt32 remainder = 0xFFFFFFFF;

        foreach (byte msgByte in augmentedMsg)
        
            byte reversedMsgByte = Reverse(msgByte);
            remainder = ((remainder << 8) | Convert.ToUInt32(reversedMsgByte)) ^ crc32_table[((remainder >> 24)) & 0xFF];
        

        remainder = Reverse(~remainder);
        return remainder;
    

而如果我使用下面的代码(避免消息扩充)会产生正确的结果。

public static UInt32 GenerateCRC_32_from_Table(byte[] message)
    
        UInt32 remainder = 0xFFFFFFFF;

        foreach (byte msgByte in message)
        
            byte reversedMsgByte = Reverse(msgByte);
            remainder = (remainder << 8) ^ crc32_table[((remainder >> 24) ^ Convert.ToUInt32(reversedMsgByte)) & 0xFF];
        

        remainder = Reverse(~remainder);
        return remainder;
    

cmets中提到的Reverse()和poly32:**

    const UInt32 poly32 = 0x04C11DB7;

    public static UInt32 Reverse(UInt32 message)
    
        UInt32 msgReversed = 0;
        for (int i = 0; i < 32; i++)
        
            msgReversed = ((message & 0x80000000) >> (31 - i)) | msgReversed;
            message = message << 1;
        
        return msgReversed;
    

    public static byte Reverse(byte message)
    
        byte msgReversed = 0;
        for (int i = 0; i < 8; i++)
        
            msgReversed = (byte)(((byte)((byte)(message) & 0x80) >> (7 - i)) | msgReversed);
            message = (byte)(message << 1);
        
        return msgReversed;
    

【问题讨论】:

Reverse 是做什么的?我没有看到任何代码。 另外你没有定义poly32 感谢您的回复。抱歉,我现在没有代码,因为我在不同的地方,所以几天后我会粘贴我用于反向的代码。 Reverse() 仅反映二进制数据,您可以在我的输出中看到 Reverse 的示例用法。 XOR ^ 0xFFFFFFFF : 11011000011000011001111111100011(D8619FE3) Reversed the Abv : 11000111111110011000011000011011(C7F9861B)。也很抱歉没有定义“poly32”,我在第一个示例中将“poly”重命名为“poly32”,所以“const UInt32 poly32 = 0x04C11DB7;”是定义。谢谢! @Mark Adler 我已经更新了问题的详细信息。谢谢! 【参考方案1】:

您所指的标准CRC被反映,即位被反转,它用0xfffffff初始化,最终的CRC用0xffffffff异或。

您生成的 CRC 的位未反转,初始 CRC 为零,且末尾没有异或。

通常要实现位反转 CRC,您将输入字节保持原样,但反映多项式并朝另一个方向移动。输入字节被送入 CRC 的底部而不是顶部。与增强消息方法相比,这也减少了四个要处理的字节总数。

更新问题:

问题中的代码尝试“增强”消息,但随后甚至不使用增强。相反,它使用从偏移量 4 开始的数据,这相当于使用从偏移量 0 开始的原始消息。

应该做的是甚至不尝试扩充消息,并将消息异或到 CRC 的顶部,而不是尝试将消息输入到 CRC 的底部。

此外,反转 CRC,应用反转的消息,然后再次反转 CRC 相当于什么都不做,而是反转多项式并朝另一个方向移动。多项式是一个常数,因此在编写代码时进行了反转,如我原来的答案中所述。 0x04c11db7 反转为0xedb88320

所以代码最终看起来像这样(在 C 中):

#include <stddef.h>
#include <stdint.h>

/* CRC-32 (Ethernet, ZIP, etc.) polynomial in reversed bit order. */
#define POLY 0xedb88320

/* Compute CRC of buf[0..len-1] with initial CRC crc.  This permits the
   computation of a CRC by feeding this routine a chunk of the input data at a
   time.  The value of crc for the first chunk should be zero. */
uint32_t crc32(uint32_t crc, const unsigned char *buf, size_t len)

    int k;

    crc = ~crc;
    while (len--) 
        crc ^= *buf++;
        for (k = 0; k < 8; k++)
            crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
    
    return ~crc;

【讨论】:

感谢您的回复!我在数组中添加了“8”个空字节(在第二个示例中)而不是“4”(如第一个示例中所示),byte[] augmentedMsg = new byte[message.Length + 8]; 所以实际上消息增强的最后四个空字节存在并被使用(扩充添加到消息的末尾)即使它从 4 开始。我已经使用前“4”个空字节将剩余部分初始化为 0xFFFFFFFF remainder = ~remainder; // Overwrite the above and Initialized the register to 0xFFFFFFFF 前四个字节从不使用,所以没有意义。 我想在奖金到期之前,在最后一分钟给你,因为你帮了我很多,先生!作为对您上述评论的回复,是的,自愿添加前四个空字节并且从不使用它没有任何意义。我只是保持它从第一个示例到第二个示例的修改最小。我的错!。因此,只有前四个字节从未使用过,但后四个字节被用作消息的扩充。我相信无论有没有增强都应该返回相同的结果,但我的结果不同(不正确)。抱歉没完没了地打扰你。谢谢!

以上是关于基本 CRC32 Wikipedia 实现不同于在线看到的标准 CRC32的主要内容,如果未能解决你的问题,请参考以下文章

CRC算法,从原理到实现

数据长度与 CRC 长度

以太网 CRC32 计算 - 软件与算法结果

快速CRC算法?

CRC32计算JavaScript实现代码

MySql crc32&&crc64函数提高字符串查询效率