学习笔记

循环冗余校验 2
1. 简介 2
2. 变体 3
3. 错误检测能力 4
4. CRC 多项式规范 4
5. 常用 CRC(按照 ITU-IEEE 规范) 4
6. CRC 与数据完整性 6
7. CRC发生碰撞的情况 6
8. 设计 CRC 多项式 6
校验原理 7
1、 循环校验码(CRC码): 7
2、 生成CRC码的基本原理: 7
3、 CRC码集选择的原则: 7
4、 CRC校验码软件生成方法: 7
CRC算法及C实现 9
一、CRC算法原理 9
查表法 12
反向算法 15
二、C语言实现 16


循环冗余校验
循环冗余校验(CRC)是一种根据网络数据封包或电脑档案等数据产生简短固定位数校验码的一种散列函数,主要用来检测或校验数据传输或者保存后可能出现的错误。生成的数字在传输或者储存之前计算出来并且附加到数据后面,然后接收方进行检验确定数据是否发生变化。一般来说,循环冗余校验的值都是32位的整数。由于本函数易于用二进制的电脑硬件使用、容易进行数学分析并且尤其善于检测传输通道干扰引起的错误,因此获得广泛应用。它是由W. Wesley Peterson在他1961年发表的论文中披露。
1. 简介
CRC为校验和的一种,是两个字节数据流采用二进制除法(没有进位,使用XOR来代替减法)相除所得到的余数。其中被除数是需要计算校验和的信息数据流的二进制表示;除数是一个长度为n + 1的预定义(短)的二进制数,通常用多项式的系数来表示。在做除法之前,要在信息数据之后先加上n个0.
CRCa 是基于有限域 GF(2) (即除以2的同余)的多项式环。简单的来说,就是所有系数都为0或1(又叫做二进制)的多项式系数的集合,并且集合对于所有的代数操作都是封闭的。例如:

2会变成0,因为对系数的加法运算都会再取2的模数. 乘法也是类似的:

我们同样可以对多项式作除法并且得到商和余数。例如, 如果我们用x3 + x2 + x除以x + 1。我们会得到:

也就是说,
(x3 + x2 + x) = (x2 + 1)(x + 1) − 1
等价于:
(x2 + x + 1)x = (x2 + 1)(x + 1) − 1
这里除法得到了商x2 + 1和余数-1,因为是奇数所以最后一位是1。
字符串中的每一位其实就对应了这样类型的多项式的系数。为了得到CRC, 我们首先将其乘以xn,这里n是一个固定多项式的阶数, 然后再将其除以这个固定的多项式,余数的系数就是CRC。
在上面的等式中,x2 + x + 1表示了本来的信息位是111, x + 1是所谓的钥匙, 而余数1(也就是x0)就是CRC. key的最高次为1, 所以我们将原来的信息乘上x1来得到x3 + x2 + x,也可视为原来的信息位补1个零成为1110。
一般来说,其形式为:

这里 M(x) 是原始的信息多项式。K(x)是n阶的“钥匙”多项式。 表示了将原始信息后面加上n个0。R(x)是余数多项式,即是CRC“校验和”。在通讯中,发送者在原始的信息数据M后附加上n位的R(替换本来附加的0)再发送。接收者收到M和R后,检查 是否能被K(x)整除。如果是,那么接收者认为该信息是正确的。值得注意的是 就是发送者所想要发送的数据。这个串又叫做codeword.。
CRCs 经常被叫做“校验和”, 但是这样的说法严格来说并不是准确的,因为技术上来说,校验“和”是通过加法来计算的,而不是CRC这里的除法。
“错误纠正编码”常常和CRCs紧密相关,其语序纠正在传输过程中所产生的错误。这些编码方式常常和数学原理紧密相关。
2. 变体
CRC 有几种不同的变体
shiftRegister 可以逆向使用,这样就需要检测最低位的值,每次向右移动一位。这就要求 polynomial 生成逆向的数据位结果。实际上这是最常用的一个变体。
可以先将数据最高位读到移位寄存器,也可以先读最低位。在通讯协议中,为了保留 CRC 的突发错误检测特性,通常按照物理层发送数据位的方式计算 CRC。
为了检查 CRC,需要在全部的码字上进行 CRC 计算,而不是仅仅计算消息(Message)的 CRC 并把它与 CRC 比较。如果结果是 0,那么就通过这项检查。这是因为码字 可以被 K(x) 整除。
移位寄存器可以初始化成 1 而不是 0。同样,在用算法处理之前,消息的最初 n 个数据位要取反。这是因为未经修改的 CRC 无法区分只有起始 0 的个数不同的两条消息。而经过这样的取反过程,CRC 就可以正确地分辨这些消息了。
CRC 在附加到消息数据流(Message stream)的时候可以进行字节取反。这样,CRC 的检查可以用直接的方法计算消息的 CRC、取反、然后与消息数据流中的 CRC 比较这个过程来完成,也可以通过计算全部的消息来完成。在后一种方法中,正确消息的结果不再是0,而是 除以 K(x) 得到的结果。这个结果叫作核验多项式 C(x),它的十六进制表示也叫作幻数。
按照惯例,使用 CRC-32 多项式以及 CRC-16-CCITT 多项式时通常都要取反。CRC-32 的核验多项式是
C(x) = x31 + x30 + x26 + x25 + x24 + x18 + x15 + x14 + x12 + x11 + x10 + x8 + x6 + x5 + x4 + x3 + x + 1。
对于要处理的资料M(x)有前置0时,用xmL(x)与M(x).xn两式相加作取反运算,使得前置的0变成1后,再作 mod 2 运算得到 CRC。公式:



例: M(x) = 01111
K(x) = x3 + x2 + 1 = 1101,这里可知 n = 3
M(x).x3 = 01111000
因 ,n = 3 故 L(x) 阶数从 2 开始
L(x) = x2 + x1 + x0 = 111
用xmL(x)求得一组 n 个 1 及 m 个 0以便与M(x).xn相加
令 m = 3 ,XmL(x) = X3L(x) = 111000 (bitwise shift)
M(x).xn + xmL(x) = 01111000 + 111000 = 10110000(使M前置的0变成1)
用 10110000 mod2 K(x) 求得余R(x)= 101, 商Q(x)=1101
T(x) = M(x).xn + L(x) + R(x) = 10110000 + 111 + 101 = 10111000送出
(其中 L(x) + R(x) = CRC)
用 10111000 mod2 1101 可校验T(x) 能被K(x)整除。

3. 错误检测能力
CRC 的错误检测能力依赖于关键多项式的阶次以及所使用的特定关键多项式。误码多项式 E(x) 是接收到的消息码字与正确消息码字的异或结果。当且仅当误码多项式能够被 CRC 多项式整除的时候 CRC 算法无法检查到错误。
由于 CRC 的计算基于除法,任何多项式都无法检测出一组全为零的数据出现的错误或者前面丢失的零。但是,可以根据 CRC 的变体来解决这个问题。
所有只有一个数据位的错误都可以被至少有两个非零系数的任意多项式检测到。误码多项式是 xk,并且 xk 只能被 的多项式 xi 整除。
CRC 可以检测出所有间隔距离小于多项式阶次的双位错误,在这种情况下的误码多项式是

如上所述,xk 不能被 CRC 多项式整除,它得到一个 xi − k + 1 项。根据定义,满足多项式整除 xi − k + 1 的 i − k 最小值就是多项是的阶次。最高阶次的多项式是本原多项式,带有二进制系数的 n 阶多项式
4. CRC 多项式规范
下面的表格略去了“初始值”、“反射值”以及“最终异或值”。
对于一些复杂的校验和来说这些十六进制数值是很重要的,如 CRC-32 以及 CRC-64。通常小于 CRC-16 的 CRC 不需要使用这些值。
通常可以通过改变这些值来得到各自不同的校验和,但是校验和算法机制并没有变化。
CRC 标准化问题
由于 CRC-12 有三种常用的形式,所以 CRC-12 的定义会有歧义
在应用的 CRC-8 的两种形式都有数学上的缺陷。
据称 CRC-16 与 CRC-32 至少有 10 种形式,但没有一种在数学上是最优的。
同样大小的 CCITT CRC 与 ITU CRC 不同,这个机构在不同时期定义了不同的校验和。
5. 常用 CRC(按照 ITU-IEEE 规范)
名称 多项式 表示法:正常或者翻转
CRC-1 x + 1
(用途:硬件,也称为奇偶校验位)
0x1 or 0x1 (0x1)
CRC-5-CCITT x5 + x3 + x + 1 (ITU G.704 标准)
0x15 (0x??)
CRC-5-USB x5 + x2 + 1 (用途:USB 信令包)
0x25 or 0x14 (0x9)
CRC-7 x7 + x3 + 1 (用途:通信系统) 0x09 or 0x48 (0x11)
CRC-8-ATM x8 + x2 + x + 1 (用途:ATM HEC) 0x07 or 0xE0 (0xC1)
CRC-8-CCITT
x8 + x7 + x3 + x2 + 1 (用途:1-Wire 总线)

CRC-8-Dallas/Maxim
x8 + x5 + x4 + 1 (用途:1-Wire bus)
0x31 or 0x8C
CRC-8 x8 + x7 + x6 + x4 + x2 + 1 0xEA(0x??)
CRC-10 x10 + x9 + x5 + x4 + x + 1 0x233 (0x????)
CRC-12 x12 + x11 + x3 + x2 + x + 1
(用途:通信系统) 0x80F or 0xF01 (0xE03)
CRC-16-Fletcher 参见 Fletcher's checksum
用于 Adler-32 A & B CRC
CRC-16-CCITT x16 + x12 + x5 + 1 (X25, V.41, Bluetooth, PPP, IrDA)
0x1021 or 0x8408 (0x0811)
CRC-16-IBM
x16 +x15 + x2 + 1 0x8005 or 0xA001 (0x4003)
CRC-16-BBS
x16 + x15 + x10 + x3 (用途:XMODEM 协议)
0x8408 (0x????)
CRC-32-Adler See Adler-32
参见 Adler-32
CRC-32-MPEG2 See IEEE 802.3
参见 IEEE 802.3
CRC-32-IEEE 802.3
x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 0x04C11DB7 or 0xEDB88320 (0xDB710641)
CRC-32C (Castagnoli) x32 + x28 + x27 + x26 + x25 + x23 + x22 + x20 + x19 + x18 + x14 + x13 + x11 + x10 + x9 + x8 + x6 + 1 0x1EDC6F41 or 0x82F63B78 (0x05EC76F1)
CRC-64-ISO x64 + x4 + x3 + x + 1
(use: ISO 3309) 0x000000000000001B or 0xD800000000000000 (0xB000000000000001)
CRC-64-ECMA-182
x64 + x62 + x57 + x55 + x54 + x53 + x52 + x47 + x46 + x45 + x40 + x39 + x38 + x37 + x35 + x33 + x32
+ x31 + x29 + x27 + x24 + x23 + x22 + x21 + x19 + x17 + x13 + x12 + x10 + x9 + x7 + x4 + x + 1
(as described in ECMA-182 p.63)
0x42F0E1EBA9EA3693 or 0xC96C5795D7870F42 (0x92D8AF2BAF0E1E85)
CRC-128 IEEE-ITU 标准。被 MD5 & SHA-1 取代

CRC-160 IEEE-ITU 标准。被 MD5 & SHA-1 取代

6. CRC 与数据完整性
尽管在错误检测中非常有用,CRC 并不能可靠地校验数据完整性(即数据没有发生任何变化),这是因为 CRC 多项式是线性结构,可以非常容易地故意改变量据而维持 CRC 不变,参见CRC and how to Reverse it中的证明。我们可以用 Message authentication code 校验数据完整性。
7. CRC发生碰撞的情况
与所有其它的散列函數一样,在一定次数的碰撞测试之后 CRC 也会接近 100% 出现碰撞。CRC 中每增加一个数据位,就会将碰撞数目减少接近 50%,如 CRC-20 与 CRC-21 相比。
理论上来讲,CRC64 的碰撞概率大约是每 18×1018 个 CRC 码出现一次。
由于 CRC 的不分解多项式特性,所以经过合理设计的较少位数的 CRC 可能会与使用较多数据位但是设计很差的 CRC 的效率相媲美。在这种情况下 CRC-32 几乎同 CRC-40 一样优秀。
8. 设计 CRC 多项式
生成多项式的选择是 CRC 算法实现中最重要的部分,所选择的多项式必须有最大的错误检测能力,同时保证总体的碰撞概率最小。多项式最重要的属性是它的长度,也就是最高非零系数的数值,因为它直接影响着计算的校验和的长度。
最常用的多项式长度有
9 位 (CRC-8)
17 位 (CRC-16)
33 位 (CRC-32)
65 位 (CRC-64)
在构建一个新的 CRC 多项式或者改进现有的 CRC 时,一个通用的数学原则是使用满足所有模运算不可分解多项式约束条件的多项式。
这种情况下的不可分解是指多项式除了 1 与它自身之外不能被任何其它的多项式整除。
生成多项式的特性可以从算法的定义中推导出来:
如果 CRC 有多于一个的非零系数,那么 CRC 能够检查出输入消息中的所有单数据位错误。
CRC 可以用于检测短于 2k 的输入消息中的所有双位错误,其中 k 是多项式的最长的不可分解部分的长度。
如果多项式可以被 x+1 整除,那么不存在可以被它整除的有奇数个非零系数的多项式。因此,它可以用来检测输入消息中的奇数个错误,就像奇偶校验函数那样。

校验原理
1、 循环校验码(CRC码):
是数据通信领域中最常用的一种差错校验码,其特征是信息字段和校验字段的长度可以任意选定。
2、 生成CRC码的基本原理:
任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应。例如:代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111。
3、 CRC码集选择的原则:
若设码字长度为N,信息字段为K位,校验字段为R位(N=K+R),则对于CRC码集中的任一码字,存在且仅存在一个R次多项式g(x),使得
V(x)=A(x)g(x)=xRm(x)+r(x);
其中: m(x)为K次信息多项式, r(x)为R-1次校验多项式,g(x)称为生成多项式:
g(x)=g0+g1x+ g2x2+...+g(R-1)x(R-1)+gRxR
发送方通过指定的g(x)产生CRC码字,接收方则通过该g(x)来验证收到的CRC码字。
4、 CRC校验码软件生成方法:
借助于多项式除法,其余数为校验字段。
例如:信息字段代码为: 1011001;对应m(x)=x6+x4+x3+1
假设生成多项式为:g(x)=x4+x3+1;则对应g(x)的代码为: 11001
x4m(x)=x10+x8+x7+x4 对应的代码记为:10110010000;
采用多项式除法: 得余数为: 1010 (即校验字段为:1010)
发送方:发出的传输字段为: 1 0 1 1 0 0 1 1 0 10
信息字段 校验字段
接收方:使用相同的生成码进行校验:接收到的字段/生成码(二进制除法)如果能够除尽,则正确.给出余数(1010)的计算步骤:
  除法没有数学上的含义,而是采用计算机的模二除法,即,除数和被除数做异或运算。进行异或运算时除数和被除数最高位对齐,按位异或。
  1011001 0000
  -11001
  --------------------------
  =01111010000
  1111010000
  -11001
  -------------------------
  =0011110000
  11110000
  -11001
  --------------------------
  =00111000
  111000
  - 11001
  -------------------
  = 001010
  利用CRC进行检错的过程可简单描述为:在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息后边,构成一个新的二进制码序列数共k+r位,然后发送出去。在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。这个规则,在差错控制理论中称为“生成多项式”。


CRC算法及C实现
一、CRC算法原理
CRC校验的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校 验用的监督码(既CRC码)r位,并附在信息后边,构成一个新的二进制码序列数共(k+r)位,最后发送出去。在接收端,则根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
16位的CRC码产生的规则是先将要发送的二进制序列数左移16位(既乘以 )后,再除以一个多项式,最后所得到的余数既是CRC码。
假设数据传输过程中需要发送15位的二进制信息 g=101001110100001,这串二进制码可表示为代数多项式g(x) = x^14 + x^12 + x^9 + x^8 + x^7 + x^5 + 1,其中g中第k位的值,对应g(x)中x^k的系数。将g(x)乘以x^m,既将g后加m个0,然后除以m阶多项式h(x),得到的(m-1)阶余项 r(x)对应的二进制码r就是CRC编码。
h(x)可以自由选择或者使用国际通行标准,一般按照h(x)的阶数m,将CRC算法称为CRC-m,比如CRC-32、CRC-64等。国际通行标准可以参看http://en.wikipedia.org/wiki/Cyclic_redundancy_check
g(x)和h(x)的除运算,可以通过g和h做xor(异或)运算。比如将11001与10101做xor运算:

明白了xor运算法则后,举一个例子使用CRC-8算法求101001110100001的效验码。CRC-8标准的h(x) = x^8 + x^7 + x^6 + x^4 + x^2 + 1,既h是9位的二进制串111010101。


经过迭代运算后,最终得到的r是10001100,这就是CRC效验码。
通过示例,可以发现一些规律,依据这些规律调整算法:
1. 每次迭代,根据gk的首位决定b,b是与gk进行运算的二进制码。若gk的首位是1,则b=h;若gk的首位是0,则b=0,或者跳过此次迭代,上面的例子中就是碰到0后直接跳到后面的非零位。

2. 每次迭代,gk的首位将会被移出,所以只需考虑第2位后计算即可。这样就可以舍弃h的首位,将b取h的后m位。比如CRC-8的h是111010101,b只需是11010101。

※蓝色表示寄存器S的首位,是需要移出的,b根据S的首位选择0或者h。黄色是需要移入寄存器的位。S'是经过位移后的S。
查表法
同样是上面的那个例子,将数据按每4位组成1个block,这样g就被分成6个block。

下面的表展示了4次迭代计算步骤,灰色背景的位是保存在寄存器中的。



经4次迭代,B1被移出寄存器。被移出的部分,不我们关心的,我们关心的是这4次迭代对B2和B3产生了什么影响。注意表中红色的部分,先作如下定义:
B23 = 00111010
b1 = 00000000
b2 = 01010100
b3 = 10101010
b4 = 11010101
b' = b1 xor b2 xor b3 xor b4
4次迭代对B2和B3来说,实际上就是让它们与b1,b2,b3,b4做了xor计算,既:
B23 xor b1 xor b2 xor b3 xor b4
可以证明xor运算满足交换律和结合律,于是:
B23 xor b1 xor b2 xor b3 xor b4 = B23 xor (b1 xor b2 xor b3 xor b4) = B23 xor b'
b1是由B1的第1位决定的,b2是由B1迭代1次后的第2位决定(既是由B1的第1和第2位决定),同理,b3和b4都是由B1决定。通过B1就可以计算出b'。另外,B1由4位组成,其一共2^4有种可能值。于是我们就可以想到一种更快捷的算法,事先将b'所有可能的值,16个值可以看成一个表;这样就可以不必进行那4次迭代,而是用B1查表得到b'值,将B1移出,B3移入,与b'计算,然后是下一次迭代。

可看到每次迭代,寄存器中的数据以4位为单位移入和移出,关键是通过寄存器前4位查表获得,这样的算法可以大大提高运算速度。
上面的方法是半字节查表法,另外还有单字节和双字节查表法,原理都是一样的——事先计算出2^8或2^16个b'的可能值,迭代中使用寄存器前8位或16位查表获得b'。
反向算法
之前讨论的算法可以称为正向CRC算法,意思是将g左边的位看作是高位,右边的位看作低位。G的右边加m个0,然后迭代计算是从高位开始,逐步将低位加入到寄存器中。在实际的数据传送过程中,是一边接收数据,一边计算CRC码,正向算法将新接收的数据看作低位。
逆向算法顾名思义就是将左边的数据看作低位,右边的数据看作高位。这样的话需要在g的左边加m个0,h也要逆向,例如正向CRC-16算法h=0x4c11db8,逆向CRC-16算法h=0xedb88320。b的选择0还是h,由寄存器中右边第1位决定,而不是左边第1位。寄存器仍旧是向左位移,就是说迭代变成从低位到高位。

二、C语言实现
1、crc-8
crc8 c语言源程序
uint8 xCal_crc(uint8 *ptr,uint32 len)
{
uint8 crc;
uint8 i;
crc = 0;
while(len--)
{
crc ^= *ptr++;
for(i = 0;i < 8;i++)
{
if(crc & 0x01)
{
crc = (crc >> 1) ^ 0x8C;
}else crc >>= 1;
}
}
return crc;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值