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: 10010110
the 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 10010110
the 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 find10010110
a CRC checksum calculation process:
Corresponds to the exclusive-OR operation:
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.
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();
}
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
可以看到,参与运算的始终只有4位,所以在移位D1数据时,参与运算的数据只有D1和D2,经过四次移位运算,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:
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