目录
简介
循环冗余校验(Cyclic redundancy check,统称“CRC”)是一种根据网络数据包或电脑文件等数据产生简短固定位数检验码的一种散列函数,主要用来检验或校验数据传输或者保存后可能出现的错误。
工作原理
循环冗余校验是利用CRC生成多项式,对原始信息进行处理,生成CRC校验码,将CRC校验码附加在原始信息之后一起发送出去,接收方接收到数据后,通过约定好的CRC生成多项式,对接收到的数据进行校验,判断数据在传输过程中是否出现错误。
CRC是基于有限域GF(2)(即除以2的同余)的多项式环。简单的来说,就是所有系数都为0或1(又叫做二进制)的多项式系数的集合,并且集合对于所有的代数操作都是封闭的。
为了便于理解,现在通过多项式的系数来表示数据。
假定:
原始信息:1011 0101
原始信息多项式:
CRC-5校验生成式的多项式(5阶):
CRC-5校验生成式:(1)0 0101 (最高位可以不用)
CRC校验码的生成:
- 将原始信息左移5位(因为采用的式CRC-5校验生成式)
- 利用模二除法获得CRC校验码
将移位后的数据(1 0110 1010 0000)模二除CRC-5校验生成式(0 0101)。
模二除法和普通的算术除法类似,但区别在于模二除的每一位除的结果不影响其他位,即不向上借位,而是采用异或的方式计算。
举例说明一下:
所以最终得到的校验码为:00100
CRC校验码多项式:
最终发送的信息:1 0110 1010 0100
接收者验证接收到的信息:
利用模二除法和约定好的CRC生成式(CRC-5),对接收到的信息(1 0110 1010 0100)进行模二除,如果整除那么可认为该信息正确。
总结这个过程,其形式:
代码实现(C/C++)
//这是通过位运算生成8位数据的crc校验码
char MyCRC::crc8_8(char data)
{
for (int i = 0; i < 8; i++) {
//当最高位是1时,左移,取异或
if (data & 0x80) {
data = (data << 1) ^ CRC8;//CRC8 = 0x07 / 0x31
}
else {
data = data << 1;
}
}
return data;
}
//通过位运算生成n个字节数据的校验码
char MyCRC::crc8_8n(char * data, int n)
{
char res = 0x00;
for (int i = 0; i < n; i++) {
res ^= *data++;
for (int j = 0; j < 8; j++) {
if (res & 0x80) {
res = (res << 1) ^ CRC8;//CRC8 = 0x07 / 0x31
}
else {
res = res << 1;
}
}
}
return res;
}
我们除了通过上述方法生成校验码,我们还可以提前生成0x00~0xFF的校验码,组成一张表,然后就直接查表。
//校验码表生成函数:
void MyCRC::crc8_table(char crc)
{
for (int i = 0; i <= 0xFF; i++) {
if (i % 16 == 0) {
cout << endl;
}
cout << "0x";
cout.fill('0');
cout.width(2);
cout.setf(ios_base::uppercase);
cout.setf(ios_base::hex, ios_base::showbase);
cout << std::hex << int(unsigned char(crc8_8(i)));
cout << ", ";
}
}
//0x00~0xFF的CRC-8(0x31)校验码表
const unsigned char CRC8Table[256] =
{
0x00,0x31,0x62,0x53,0xC4,0xF5,0xA6,0x97,0xB9,0x88,0xDB,0xEA,0x7D,0x4C,0x1F,0x2E,
0x43,0x72,0x21,0x10,0x87,0xB6,0xE5,0xD4,0xFA,0xCB,0x98,0xA9,0x3E,0x0F,0x5C,0x6D,
0x86,0xB7,0xE4,0xD5,0x42,0x73,0x20,0x11,0x3F,0x0E,0x5D,0x6C,0xFB,0xCA,0x99,0xA8,
0xC5,0xF4,0xA7,0x96,0x01,0x30,0x63,0x52,0x7C,0x4D,0x1E,0x2F,0xB8,0x89,0xDA,0xEB,
0x3D,0x0C,0x5F,0x6E,0xF9,0xC8,0x9B,0xAA,0x84,0xB5,0xE6,0xD7,0x40,0x71,0x22,0x13,
0x7E,0x4F,0x1C,0x2D,0xBA,0x8B,0xD8,0xE9,0xC7,0xF6,0xA5,0x94,0x03,0x32,0x61,0x50,
0xBB,0x8A,0xD9,0xE8,0x7F,0x4E,0x1D,0x2C,0x02,0x33,0x60,0x51,0xC6,0xF7,0xA4,0x95,
0xF8,0xC9,0x9A,0xAB,0x3C,0x0D,0x5E,0x6F,0x41,0x70,0x23,0x12,0x85,0xB4,0xE7,0xD6,
0x7A,0x4B,0x18,0x29,0xBE,0x8F,0xDC,0xED,0xC3,0xF2,0xA1,0x90,0x07,0x36,0x65,0x54,
0x39,0x08,0x5B,0x6A,0xFD,0xCC,0x9F,0xAE,0x80,0xB1,0xE2,0xD3,0x44,0x75,0x26,0x17,
0xFC,0xCD,0x9E,0xAF,0x38,0x09,0x5A,0x6B,0x45,0x74,0x27,0x16,0x81,0xB0,0xE3,0xD2,
0xBF,0x8E,0xDD,0xEC,0x7B,0x4A,0x19,0x28,0x06,0x37,0x64,0x55,0xC2,0xF3,0xA0,0x91,
0x47,0x76,0x25,0x14,0x83,0xB2,0xE1,0xD0,0xFE,0xCF,0x9C,0xAD,0x3A,0x0B,0x58,0x69,
0x04,0x35,0x66,0x57,0xC0,0xF1,0xA2,0x93,0xBD,0x8C,0xDF,0xEE,0x79,0x48,0x1B,0x2A,
0xC1,0xF0,0xA3,0x92,0x05,0x34,0x67,0x56,0x78,0x49,0x1A,0x2B,0xBC,0x8D,0xDE,0xEF,
0x82,0xB3,0xE0,0xD1,0x46,0x77,0x24,0x15,0x3B,0x0A,0x59,0x68,0xFF,0xCE,0x9D,0xAC };
//0x00~0xFF的CRC-8(0x07)校验码表
const unsigned char CRC8Table[256] =
{
0x00,0x07,0x0E,0x09,0x1C,0x1B,0x12,0x15,0x38,0x3F,0x36,0x31,0x24,0x23,0x2A,0x2D,
0x70,0x77,0x7E,0x79,0x6C,0x6B,0x62,0x65,0x48,0x4F,0x46,0x41,0x54,0x53,0x5A,0x5D,
0xE0,0xE7,0xEE,0xE9,0xFC,0xFB,0xF2,0xF5,0xD8,0xDF,0xD6,0xD1,0xC4,0xC3,0xCA,0xCD,
0x90,0x97,0x9E,0x99,0x8C,0x8B,0x82,0x85,0xA8,0xAF,0xA6,0xA1,0xB4,0xB3,0xBA,0xBD,
0xC7,0xC0,0xC9,0xCE,0xDB,0xDC,0xD5,0xD2,0xFF,0xF8,0xF1,0xF6,0xE3,0xE4,0xED,0xEA,
0xB7,0xB0,0xB9,0xBE,0xAB,0xAC,0xA5,0xA2,0x8F,0x88,0x81,0x86,0x93,0x94,0x9D,0x9A,
0x27,0x20,0x29,0x2E,0x3B,0x3C,0x35,0x32,0x1F,0x18,0x11,0x16,0x03,0x04,0x0D,0x0A,
0x57,0x50,0x59,0x5E,0x4B,0x4C,0x45,0x42,0x6F,0x68,0x61,0x66,0x73,0x74,0x7D,0x7A,
0x89,0x8E,0x87,0x80,0x95,0x92,0x9B,0x9C,0xB1,0xB6,0xBF,0xB8,0xAD,0xAA,0xA3,0xA4,
0xF9,0xFE,0xF7,0xF0,0xE5,0xE2,0xEB,0xEC,0xC1,0xC6,0xCF,0xC8,0xDD,0xDA,0xD3,0xD4,
0x69,0x6E,0x67,0x60,0x75,0x72,0x7B,0x7C,0x51,0x56,0x5F,0x58,0x4D,0x4A,0x43,0x44,
0x19,0x1E,0x17,0x10,0x05,0x02,0x0B,0x0C,0x21,0x26,0x2F,0x28,0x3D,0x3A,0x33,0x34,
0x4E,0x49,0x40,0x47,0x52,0x55,0x5C,0x5B,0x76,0x71,0x78,0x7F,0x6A,0x6D,0x64,0x63,
0x3E,0x39,0x30,0x37,0x22,0x25,0x2C,0x2B,0x06,0x01,0x08,0x0F,0x1A,0x1D,0x14,0x13,
0xAE,0xA9,0xA0,0xA7,0xB2,0xB5,0xBC,0xBB,0x96,0x91,0x98,0x9F,0x8A,0x8D,0x84,0x83,
0xDE,0xD9,0xD0,0xD7,0xC2,0xC5,0xCC,0xCB,0xE6,0xE1,0xE8,0xEF,0xFA,0xFD,0xF4,0xF3};
//0x00~0xFF的CRC-8(0x8D)校验码表
const unsigned char CRC8Table[256] =
{
0x00,0x8D,0x97,0x1A,0xA3,0x2E,0x34,0xB9,0xCB,0x46,0x5C,0xD1,0x68,0xE5,0xFF,0x72,
0x1B,0x96,0x8C,0x01,0xB8,0x35,0x2F,0xA2,0xD0,0x5D,0x47,0xCA,0x73,0xFE,0xE4,0x69,
0x36,0xBB,0xA1,0x2C,0x95,0x18,0x02,0x8F,0xFD,0x70,0x6A,0xE7,0x5E,0xD3,0xC9,0x44,
0x2D,0xA0,0xBA,0x37,0x8E,0x03,0x19,0x94,0xE6,0x6B,0x71,0xFC,0x45,0xC8,0xD2,0x5F,
0x6C,0xE1,0xFB,0x76,0xCF,0x42,0x58,0xD5,0xA7,0x2A,0x30,0xBD,0x04,0x89,0x93,0x1E,
0x77,0xFA,0xE0,0x6D,0xD4,0x59,0x43,0xCE,0xBC,0x31,0x2B,0xA6,0x1F,0x92,0x88,0x05,
0x5A,0xD7,0xCD,0x40,0xF9,0x74,0x6E,0xE3,0x91,0x1C,0x06,0x8B,0x32,0xBF,0xA5,0x28,
0x41,0xCC,0xD6,0x5B,0xE2,0x6F,0x75,0xF8,0x8A,0x07,0x1D,0x90,0x29,0xA4,0xBE,0x33,
0xD8,0x55,0x4F,0xC2,0x7B,0xF6,0xEC,0x61,0x13,0x9E,0x84,0x09,0xB0,0x3D,0x27,0xAA,
0xC3,0x4E,0x54,0xD9,0x60,0xED,0xF7,0x7A,0x08,0x85,0x9F,0x12,0xAB,0x26,0x3C,0xB1,
0xEE,0x63,0x79,0xF4,0x4D,0xC0,0xDA,0x57,0x25,0xA8,0xB2,0x3F,0x86,0x0B,0x11,0x9C,
0xF5,0x78,0x62,0xEF,0x56,0xDB,0xC1,0x4C,0x3E,0xB3,0xA9,0x24,0x9D,0x10,0x0A,0x87,
0xB4,0x39,0x23,0xAE,0x17,0x9A,0x80,0x0D,0x7F,0xF2,0xE8,0x65,0xDC,0x51,0x4B,0xC6,
0xAF,0x22,0x38,0xB5,0x0C,0x81,0x9B,0x16,0x64,0xE9,0xF3,0x7E,0xC7,0x4A,0x50,0xDD,
0x82,0x0F,0x15,0x98,0x21,0xAC,0xB6,0x3B,0x49,0xC4,0xDE,0x53,0xEA,0x67,0x7D,0xF0,
0x99,0x14,0x0E,0x83,0x3A,0xB7,0xAD,0x20,0x52,0xDF,0xC5,0x48,0xF1,0x7C,0x66,0xEB};
//0x00~0xFF的CRC-8(0xD5)校验码表
const unsigned char CRC8Table[256] =
{
0x00,0xD5,0x7F,0xAA,0xFE,0x2B,0x81,0x54,0x29,0xFC,0x56,0x83,0xD7,0x02,0xA8,0x7D,
0x52,0x87,0x2D,0xF8,0xAC,0x79,0xD3,0x06,0x7B,0xAE,0x04,0xD1,0x85,0x50,0xFA,0x2F,
0xA4,0x71,0xDB,0x0E,0x5A,0x8F,0x25,0xF0,0x8D,0x58,0xF2,0x27,0x73,0xA6,0x0C,0xD9,
0xF6,0x23,0x89,0x5C,0x08,0xDD,0x77,0xA2,0xDF,0x0A,0xA0,0x75,0x21,0xF4,0x5E,0x8B,
0x9D,0x48,0xE2,0x37,0x63,0xB6,0x1C,0xC9,0xB4,0x61,0xCB,0x1E,0x4A,0x9F,0x35,0xE0,
0xCF,0x1A,0xB0,0x65,0x31,0xE4,0x4E,0x9B,0xE6,0x33,0x99,0x4C,0x18,0xCD,0x67,0xB2,
0x39,0xEC,0x46,0x93,0xC7,0x12,0xB8,0x6D,0x10,0xC5,0x6F,0xBA,0xEE,0x3B,0x91,0x44,
0x6B,0xBE,0x14,0xC1,0x95,0x40,0xEA,0x3F,0x42,0x97,0x3D,0xE8,0xBC,0x69,0xC3,0x16,
0xEF,0x3A,0x90,0x45,0x11,0xC4,0x6E,0xBB,0xC6,0x13,0xB9,0x6C,0x38,0xED,0x47,0x92,
0xBD,0x68,0xC2,0x17,0x43,0x96,0x3C,0xE9,0x94,0x41,0xEB,0x3E,0x6A,0xBF,0x15,0xC0,
0x4B,0x9E,0x34,0xE1,0xB5,0x60,0xCA,0x1F,0x62,0xB7,0x1D,0xC8,0x9C,0x49,0xE3,0x36,
0x19,0xCC,0x66,0xB3,0xE7,0x32,0x98,0x4D,0x30,0xE5,0x4F,0x9A,0xCE,0x1B,0xB1,0x64,
0x72,0xA7,0x0D,0xD8,0x8C,0x59,0xF3,0x26,0x5B,0x8E,0x24,0xF1,0xA5,0x70,0xDA,0x0F,
0x20,0xF5,0x5F,0x8A,0xDE,0x0B,0xA1,0x74,0x09,0xDC,0x76,0xA3,0xF7,0x22,0x88,0x5D,
0xD6,0x03,0xA9,0x7C,0x28,0xFD,0x57,0x82,0xFF,0x2A,0x80,0x55,0x01,0xD4,0x7E,0xAB,
0x84,0x51,0xFB,0x2E,0x7A,0xAF,0x05,0xD0,0xAD,0x78,0xD2,0x07,0x53,0x86,0x2C,0xF9};
CRC校验生成式
生成多项式的选择是CRC算法实现中最重要的部分,所选择的多项式必须有最大的错误检测能力,同时保证总体的碰撞概率最小。多项式最重要的属性是它的长度,也就是最高非零系数的数值,因为它直接影响着计算的校验和的长度。
与所有其它的散列函数一样,在一定次数的碰撞测试之后CRC也会接近100%出现碰撞。CRC中每增加一个数据位,碰撞机率就会减少接近50%,如CRC-20与CRC-21相比。
理论上来讲,CRC64的碰撞概率大约是每18×1018个CRC码出现一次。
由于CRC的不分解多项式特性,所以经过合理设计的较少位数的CRC可能会与使用较多数据位但是设计很差的CRC的效率相媲美。在这种情况下CRC-32几乎同CRC-40一样优秀。
在构建一个新的CRC多项式或者改进现有的CRC时,一个通用的数学原则是使用满足所有模运算不可分解多项式约束条件的多项式。这种情况下的不可分解是指多项式除了1与它自身之外不能被任何其它的多项式整除。
部分常用的CRC校验生成式:
名称 | 用途 | 表示法 |
---|---|---|
CRC-1 | 硬件,又称奇偶检验位 | 0x1 |
CRC-5-CCITT | ITU G.704标准 | 0xB |
CRC-5-USB | USB信令包 | 0x05 |
CRC-7 | 通信系统 | 0x09 |
CRC-8-ATM | ATM HEC,PMBUS | 0x07 |
CRC-8-CCITT | 1-Wire总线 | 0x8D |
CRC-8-Dallas/Maxim | 1-Wire bus | 0x31 |
CRC-8 | - | 0xD5 |
写在最后
更多内容,请见维基百科