了解CRC32值作为除法余数

时间:2018-10-05 20:18:25

标签: hash crc crc32

我正在努力理解CRC算法。我一直在阅读this tutorial,如果我正确理解它,CRC值只是除法的余数,其中消息用作被除数,除数是预定义的值-用一种特殊的多项式算法执行。它看起来很简单,所以我尝试实现CRC-32:

public static uint Crc32Naive(byte[] bytes)
{
    uint poly = 0x04c11db7; // (Poly)
    uint crc = 0xffffffff; // (Init)

    foreach (var it in bytes)
    {
        var b = (uint)it;
        for (var i = 0; i < 8; ++i)
        {
            var prevcrc = crc;

            // load LSB from current byte into LSB of crc (RefIn)
            crc = (crc << 1) | (b & 1); 
            b >>= 1;

            // subtract polynomial if we've just popped out 1 
            if ((prevcrc & 0x80000000) != 0) 
                crc ^= poly;
        }
    }

    return Reverse(crc ^ 0xffffffff); // (XorOut) (RefOut)
}

(其中Reverese函数将位顺序颠倒)

应该类似于以下划分方法(进行一些附加调整):

            1100001010
       _______________
10011 ) 11010110110000
        10011,,.,,....
        -----,,.,,....
         10011,.,,....
         10011,.,,....
         -----,.,,....
          00001.,,....
          00000.,,....
          -----.,,....
           00010,,....
           00000,,....
           -----,,....
            00101,....
            00000,....
            -----,....
             01011....
             00000....
             -----....
              10110...
              10011...
              -----...
               01010..
               00000..
               -----..
                10100.
                10011.
                -----.
                 01110
                 00000
                 -----
                  1110 = Remainder

对于:0x00函数返回正确的0xd202ef8d,但对于0x01-0xd302ef8d而不是0xa505df1b(我一直在使用{{3 }}以验证我的结果)。

我的实施解决方案对我来说更有意义:将股息增加1只能将提醒更改为1,对吧?但事实证明,结果看起来应该完全不同。因此,显然我缺少明显的东西。它是什么?改变分红中的最低有效数字会对结果有多大影响?

1 个答案:

答案 0 :(得分:0)

这是一个左移CRC的示例,它模拟除法,CRC初始化为0,并且crc没有补码或取反。该示例代码模拟了一个除法,其中4个字节的零被附加到bytes []({bytes [],0,0,0,0}是被除数,除数是0x104c11db7,未使用商,而余数是CRC)。

public static uint Crc32Naive(byte[] bytes)
{
    uint poly = 0x04c11db7; // (Poly is actually 0x104c11db7)
    uint crc = 0;           // (Init)

    foreach (var it in bytes)
    {
        crc ^= (((int)it)<<24);     // xor next byte to upper 8 bits of crc
        for (var i = 0; i < 8; ++i) // cycle the crc 8 times
        {
            var prevcrc = crc;
            crc = (crc << 1); 
            // subtract polynomial if we've just popped out 1 
            if ((prevcrc & 0x80000000) != 0) 
                crc ^= poly;
        }
    }
    return crc;
}

将CRC初始化为零以外的值是很常见的,但是对CRC进行后补码并不常见,而且我不知道有任何CRC会对CRC进行位反转。

CRC的另一种变化是右移,通常用于模拟硬件,在该硬件中,数据以字节的最低有效位优先发送。