[Technical Stack] The principle and the CRC check code implementation C # CRC16, CRC32 checksum calculated FCS

1.CRC, what is FCS

The CRC, stands for Cyclic Redundancy Check, the Chinese name of the cyclic redundancy check, a fixed number of bits to produce a brief check code according to a network packet or a computer data file, etc. A channel coding technology, mainly used to detect or verify after the data transmission error or saved may arise. It is the use of the principle of the division and the remainder to make the error detection.

FCS, Full Frame Check Sequence, the Chinese name of a frame check sequence, known as the end of the frame, i.e. the protocol data unit tail field computer network data link layer (frame), was a 4-byte cyclic redundancy check code .

NOTE: CRC cyclic redundancy check and the frame check sequence FCS is a separate concept, CRC error checking is a method, FCS is a frame check code tail, FCS check the CRC method may be used, other checking may be employed method.

2.CRC algorithm principle

We can put any string of binary data is represented as a corresponding polynomial. such as:

Binary data: 1100101
polynomial: $ x ^ 6 + x ^ 5 + x ^ 2 + 1 $

Polynomial: $ x ^ 6 + x ^ 4 + x ^ 3 + x ^ 2 + 1 $
binary data: 1011101

With such a correspondence relationship, CRC check on the binary data may be calculated using polynomial arithmetic rule check.
CRC校验算法正是采用了模2除法,在数据处理里的具体表现为异或运算。

CRC specific calculation rule: binary data is assumed to be transmitted is: 10010110the corresponding m-th order polynomial: $ M = x ^ 7 + x ^ 4 + x ^ 2 + x ^ 1 $, the divisor of h-order polynomial : $ H = x ^ 4 + x $, corresponding to the binary code is: 10010, the first M multiplied by $ x ^ h $, M is about to add back the binary data corresponding to the h 0, h is then divided by the order of the polynomial H , h-1 in order to obtain a remainder term R is the data of binary data corresponding to 10010110the CRC code.

3. Calculate the CRC

3.1. Hand calculation of CRC

M and H polynomial division, can be calculated modulo 2 division. The following is a generator polynomial for the H find10010110a CRC checksum calculation process:
crc_handle_item.png

Corresponds to the exclusive-OR operation:
crc_handle_item_xor.png
i.e., after the data are other custom calculation, based on the calculation phenomenon can be summarized by way of example some rules:

1. Each XOR operation, when the first 1 from left to right when it generator polynomial H exclusive OR operation, and then a left; is 0 when the first data only when the left one.

2. Each data XOR operation, the first bound is 0 for the first time as an exclusive-OR operation is performed, the first generating polynomial must be 1. When the exclusive-OR operation is required to be discarded H in the first place, after the rejection of H ' , and then the data directly to the left and an H' exclusive or.
crc_handle_item_xor_move_bit.png
3. Each operation involved in computing a first h-bit data can be stored in a register S by h bit binary data, the first h-bit memory data to this register. Every time the first arithmetic register first removed, and then bit into the binary data, and then participate in operation, the value of the final register the CRC value.

3.2.C # code calculates the CRC

//代码验证如下:
static void Main(string[] args)
{
    int data = 0b10010110;
    int ploy = 0b0010;
    ploy <<= 4;
    Console.WriteLine($"第0次运算结果:"+Convert.ToString(data, 2));
    for (int i = 0; i < 8; i++)
    {
        if ((data & 0b10000000) == 0b10000000)
        {
            data = (data << 1) ^ ploy;

        }
        else
        {
            data <<= 1;
        }

        Console.WriteLine($"第{i+1}次运算结果:"+Convert.ToString(data, 2));
    }
    Console.WriteLine($" 最终运算结果:"+Convert.ToString(data, 2));          
    Console.ReadKey();
}

crc_handle_item_xor_code_result.png

Here with the fifth to eighth bit as a four-bit register int can be seen consistent with hand calculations, calculated parity bit last 1100.

4. The look-up table

crc_handle_item_xor_table.png

可以看到,参与运算的始终只有4位,所以在移位D1数据时,参与运算的数据只有D1D2,经过四次移位运算,D1被移除寄存器,这个时候受到影响的只有D2。而将D2的初值经过四次异或运算后的值就可以获得四次移位后的新数据$D2'=D2\bigoplus H1 \bigoplus H2\bigoplus H3\bigoplus H4 = D2 \bigoplus \sum{h}$。

每一次D2是异或0还是异或生成多项式H',与D2本身的值无关,仅与D1中被移除的数据有关(首位为0还是1),所以这里引入了一个查表法,即先将所有可能的D1组合都计算出对应的$\sum{h}$,一次性移除四位,然后以$D2\bigoplus{\sum{h}}$即可以获得D2'

生成多项式为H,则一共有$2^h$种可能,代码如下:

class CalcByCrcTable
{
    private byte[] CrcTable;
    private void CteateTable()
    {
        int ploy = 0b0010;            
        CrcTable = new byte[(int)Math.Pow(2,4)];
        ploy <<= 4;
        for (int i = 0; i < CrcTable.Length ; i++)
        {
            int data = i<<4;
            for (int j = 0; j < 4; j++)
            {
                if ((data & 0b10000000) == 0b10000000)
                {
                    data = (data << 1) ^ ploy;
                }
                else
                {
                    data <<= 1;
                }                  
            }
            CrcTable[i] = Convert.ToByte((data & 0xf0)>>4);
        }
    }
    public byte CalcCrc()
    {
        CteateTable();
        int data = 0b10010110;
        byte crchigh4 = CrcTable[(data>>4)&0x0f];//用查表法先查到data的高四位1001的crc值;
        byte value = Convert.ToByte((data & 0x0f) ^ crchigh4);//将高四位的CRC与低四位异或,得到移位四次后的数据值;
        byte crc = CrcTable[value]; //在用移位后的数据值查出数据的CRC校验码;
        return crc;

    }
}

 static void Main(string[] args)
 {
        CalcByCrcTable calcByCrcTable = new CalcByCrcTable();
        byte crc = calcByCrcTable.CalcCrc();           
        Console.WriteLine($" CRC校验码为:" + Convert.ToString(crc, 2));
        Console.ReadKey();
}

//打印结果如下

CRC校验码为:1100

可以看到与前面的计算法结果一致。

5.反向校验

上面所诉的均为正向检验(Normal),当然也有反向校验(Reversed),反向校验是将数据和生成多项式均进行了一个镜像,当然算法也需要镜像,即镜像后从右往左运算。

5.1手工计算CRC反向校验码

原二进制数据:10010110

原生成多项式:0010

Forward CRC checksum: 1100

Mirror binary data: 01101001

Image generating polynomial: 0100

Mirror algorithm:

crc_handle_item_xor_reversed_move_bit.png

Reverse CRC checksum: 0011

5.2.C # reverse calculates the CRC check code Code

class CalcByCrcTable
{
    private byte[] CrcTable;
    private void CteateReversedTable()
    {
        int ploy = 0b0100;
        CrcTable = new byte[(int)Math.Pow(2, 4)];           
        for (int i = 0; i < CrcTable.Length; i++)
        {
            int data = i;
            for (int j = 0; j < 4; j++)
            {
                if ((data & 1) == 1)
                {
                    data = (data >> 1) ^ ploy;
                }
                else
                {
                    data >>= 1;
                }
            }
            CrcTable[i] = Convert.ToByte((data & 0x0f));
        }
    }
 public byte CalcReversedCrc()
    {
        CteateReversedTable();
        int data = 0b01101001;
        byte crclow4 = CrcTable[data & 0x0f];//用用查表法先查到data的低四位1001的crc值;
        byte value = Convert.ToByte(((data>>4) & 0x0f) ^ crclow4);//将第四位的CRC与低四位异或,得到移位四次后的数据值;
        byte crc = CrcTable[value]; //在用移位后的数据值查出数据的CRC校验码;
        return crc;

    }
}

 static void Main(string[] args)
{
    CalcByCrcTable calcByCrcTable = new CalcByCrcTable();
    byte crc = calcByCrcTable.CalcReversedCrc();           
    Console.WriteLine($" CRC反向校验码为:" + Convert.ToString(crc, 2));
    Console.ReadKey();
}

// print the results as follows

CRC check code for the reverse: 11

CRC16 checksum calculated look-up table 6.C #

//多线程使用时请注意干扰 
class CalcOnCrc16
 {
    private ushort[] Crc16NormalTable;

    private ushort[] Crc16ReversedTable;

    private void CreateNormalCrc16Table(ushort ploy)
    {
       ushort data;
       Crc16NormalTable = new ushort[256];
       int i, j;
       for (i = 0; i < 256; i++)
       {
           data = (ushort)(i << 8);
           for (j = 0; j < 8; j++)
           {
               if ((data & 0x8000) == 0x8000)
                   data = Convert.ToUInt16((ushort)(data << 1) ^ ploy);
               else
                   data <<= 1;                    
           }
           Crc16NormalTable[i] = data;
       }
    }

    private void CreateReversedCrc16Table(ushort ploy)
    {
       ushort data;
       Crc16ReversedTable = new ushort[256];
       int i, j;
       for (i = 0; i < 256; i++)
       {
           data = (ushort)i;
           for (j = 0; j < 8; j++)
           {
               if ((data & 1) == 1)
                   data = Convert.ToUInt16((ushort)(data >>1) ^ ploy);
               else
                   data >>= 1;
           }
           Crc16ReversedTable[i] = data;
       }
    }

    /// <summary>
    /// 正向计算CRC16校验码
    /// </summary>
    /// <param name="bytes">校验数据</param>
    /// <param name="poly">生成多项式</param>
    /// <param name="crcInit">校验码初始值</param>
    /// <returns></returns>
    public ushort CalcNoemalCrc16(byte[] bytes,ushort poly,ushort crcInit)
    {
        CreateNormalCrc16Table(poly);
   
        ushort crc = crcInit;
        for (int i = 0; i < bytes.Length; i++)
        {
            crc = Convert.ToUInt16((ushort)(crc << 8) ^ Crc16NormalTable[((crc >> 8) & 0xff) ^ bytes[i]]);
        }
        return crc;
    }

     /// <summary>
     /// 反向计算CRC16校验码
     /// </summary>
     /// <param name="bytes">校验数据</param>
     /// <param name="poly">反向生成多项式</param>
     /// <param name="crcInit">校验码初始值</param>
     /// <returns></returns>
    public ushort CalcReversedCrc16(byte[] bytes, ushort poly, ushort crcInit)
    {
        CreateReversedCrc16Table(poly);
   
        ushort crc = crcInit;
        for (int i = 0; i < bytes.Length; i++)
        {
            crc = Convert.ToUInt16((ushort)(crc >> 8) ^ Crc16ReversedTable[(crc & 0xff) ^ bytes[i]]);
        }
        return crc;
    }
 }

CRC32 checksum calculation table method 7.C #

class CalcOnCrc32
{
    private uint[] Crc32NormalTable;
    
    private uint[] Crc32ReversedTable;

    private void CreateNormalCrc32Table(uint ploy)
    {
        uint data;
        Crc32NormalTable = new uint[256];
        int i, j;
        for (i = 0; i < 256; i++)
        {
            data = (uint)(i << 24);
            for (j = 0; j < 8; j++)
            {
                if ((data & 0x80000000) == 0x80000000)
                    data = Convert.ToUInt32((uint)(data << 1) ^ ploy);
                else
                    data <<= 1;
            }
            Crc32NormalTable[i] = data;
        }
    }

    private void CreateReversedCrc32Table(uint ploy)
    {
        uint data;
        Crc32ReversedTable = new uint[256];
        int i, j;
        for (i = 0; i < 256; i++)
        {
            data = (uint)i;
            for (j = 0; j < 8; j++)
            {
                if ((data & 1) == 1)
                    data = Convert.ToUInt32((uint)(data >> 1) ^ ploy);
                else
                    data >>= 1;
            }
            Crc32ReversedTable[i] = data;
        }
    }

    /// <summary>
    /// 正向计算CRC32校验码
    /// </summary>
    /// <param name="bytes">校验数据</param>
    /// <param name="poly">生成多项式</param>
    /// <param name="crcInit">校验码初始值</param>
    /// <returns></returns>
    public uint CalcNoemalCrc32(byte[] bytes, uint poly, uint crcInit)
    {
        CreateNormalCrc32Table(poly);
        uint crc = crcInit;
        for (int i = 0; i < bytes.Length; i++)
        {
            crc = Convert.ToUInt32((uint)(crc << 8) ^ Crc32NormalTable[((crc >> 24) & 0xff) ^ bytes[i]]);
        }
        return crc;
    }

    /// <summary>
    /// 反向计算CRC32校验码
    /// </summary>
    /// <param name="bytes">校验数据</param>
    /// <param name="poly">反向生成多项式</param>
    /// <param name="crcInit">校验码初始值</param>
    /// <returns></returns>
    public uint CalcReversedCrc32(byte[] bytes, uint poly, uint crcInit)
    {
        CreateReversedCrc32Table(poly);
        uint crc = crcInit;
        for (int i = 0; i < bytes.Length; i++)
        {
            crc = Convert.ToUInt32((uint)(crc >> 8) ^ Crc32ReversedTable[(crc & 0xff) ^ bytes[i]]);
        }
        return crc;
    }
}

Reference material

Cyclic Redundancy Check (CRC) algorithm theory

CRC lookup table method to derive the code and achieve more

CRC (Cyclic Redundancy Check) is calculated Online

Guess you like

Origin www.cnblogs.com/mjoin/p/11607114.html