CRC概述

循环冗余校验(Cyclic Redundancy Check, CRC) 又称多项式码,是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术

主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用二进制除法及余数的原理来作错误侦测的。

原理

基本思想

发收方与接收方实现选定一个多项式P(x)P(x),该多项式可以与二进制码一一对应,我们要求该二进制数最高位和最低位必须为1,而这个二进制数就作为 除数

接下来,我们以需要发送的NN数据序列被除数, 两者进行“模2除法”,得到的DD 位的 余数 即校验码,也叫 帧检测序列(FCS),将校验码附在数据序列后面生成一个新序列(共D+ND+N 位)发送给接收端。

到达接收端后,把接收到的新序列除以这个选定的除数,无差错的结果应该是余数为0。如果有余数,则表明该数据在传输过程中出现了差错。

数学解释

现有需要传输的数据流M=m0m1mN1M=m_0m_1\cdots m_{N-1},由N=M  bitN=|M|\;bit 组成,mk{0,1}m_k\in\{0,1\}.
那么,其大小可以用22 的多项式表示如下(不如说任意二进制数都能如此表示):

M=k=0N12(N1)kmkM=\sum_{k=0}^{N-1}2^{(N-1)-k}\cdot m_k

更一般地,可表示为对任一单变量xx 的多项式函数:

M(x)=k=0N1xN1kmkmGF(2)={0,1}M(x)=\sum_{k=0}^{N-1}x^{N-1-k}\cdot m_k\quad m\in GF(2)=\{0,1\}

其中,GF()GF(·) 表示的是一种 有限域|finite field 又称 伽罗尔域|Galois field。而这里的多项式表示的是模2同余多项式环。例如有:

(x3+x)+(x+1)=x3+2x+1x3+1(x^3+x)+(x+1)=x^3+2x+1\equiv x^3+1

其中x2x^2 前的系数因为模二余0,所以消失了。

如果给定一个阶数为D:=deg(P(x))D:=\text{deg}(P(x)) 的多项式P(x)P(x). 那么,我们就可以定义 CRC帧检测序列 为:

FCSP(M)=(M(x)xD)modP(x)FCS_P(M)=\left(M(x)\cdot x^D\right)\mod P(x)

显然,(M(x)xD+FCSP(M))modP(x)0\left(M(x)\cdot x^D+FCS_P(M)\right)\mod P(x)\equiv 0

M(x)=x2+x+1,P(x)=x+1M(x)=x^2+x+1,P(x)=x+1 为例,由长除法得:

  x2+1x+1)      x3+x2+x        x3+x2     x    x+1    1\begin{aligned} & \quad\;x^2+1 \\ x+1 & \overline{)\;\;\;x^3+x^2+x\quad\quad } \\ & \underline{\;\;\;\;x^3+x^2\quad\quad}\quad\quad\ \\ & \quad\quad\quad\quad \quad \;\;x \\ & \underline{\quad\quad\quad\quad\quad\;\; x+1\quad} \\ & \quad\quad\quad\quad\quad\quad\;\;-1\\ \end{aligned}

即是:M(x)x=P(x)(x2+1)1M(x)\cdot x=P(x)\cdot (x^2+1)-1. 这里的 余数 1 即是帧检测序列。
所以有:M(x)x+1=P(x)(x2+1)(M(x)x+1)modP(x)=0M(x)\cdot x+1=P(x)\cdot(x^2+1)\Rightarrow (M(x)·x+1)\mod P(x)=0

二进制表示

我们将上述示例退化为二进制表示,即M(x)M(x)\to111,P(x)P(x)\to11.
进而有M(x)xM(x)·x\to1110,相当于将二进制数右补D=1D=10(因为P(x)P(x)的阶数为1)

对二者进行模二除法(加法不进位,减法不借位,事实上正好是对二进制按位异或):

  10111)      1110  11   10  11      1\begin{aligned} & \quad\;101 \\ 11 & \overline{)\;\;\;1110\quad\quad } \\ & \underline{\quad\;11\quad}\quad\quad\ \\ & \quad\quad\;10 \\ & \underline{\quad\quad\;11\quad} \\ & \quad\quad\;\;\;1\\ \end{aligned}

从而余数 1 即为结果。显然有M(x)x+1M(x)·x+1\to 111111 的模为0.

常用算法选取

CRC算法名称多项式公式多项式初始值结果异或输入值反转输出值反转
CRC-4/ITUx^4^ + x + 14030000truetrue
CRC-5/EPCx^4^ + x^3^ + 15090900falsefalse
CRC-5/ITUx^5^ + x^4^ + x^2^ + 15150000truetrue
CRC-5/USBx^5^ + x^2^ + 15051F1Ftruetrue
CRC-6/ITUx^6^ + x + 16030000truetrue
CRC-7/MMCx^7^ + x^3^ + 17090000falsefalse
CRC-8x^8^ + x^2^ + x + 18070000falsefalse
CRC-8/ITUx^8^ + x^2^ + x + 18070055falsefalse
CRC-8/ROHCx^8^ + x^2^ + x + 1807FF00truetrue
CRC-8/MAXIMx^8^ + x^5^ + x^4^ + 18310000truetrue

硬件实现

以 CRC8 为例:P(x)=x8+x2+x+1P(x)=x^8+x^2+x+10x07,二进制为:100000111)为多项式,假设需要计算计算一个字节:0xA5(二进制为:1010 0101

结合数学原理,我们甚至可以把模二除法这个过程简化为左移+异或。这使得硬件实现成为可能。

  1. 0xA5 左移8位,移位后数据为: 1010 0101 0000 0000
  2. 先进行高9位异或, 1010 0101 0000 0000。

④当多项式最高位为1,才进行异或计算,异或后最高位为0,下次也不需要异或,这样需要采用代码计算的方式,就可以把最高位去掉不需要异或,最后结果是一样的。

如图所示:

模二除法实例

算法之一

给出如下算法(无脑简单):

  1. 将目标数据序列二进制数据以string形式保存

  2. 将除数(多项式对应的二进制数据)也以string类型保存

  3. 对目标数据string补相应个数的0,如:个数n=8

  4. 将除数字符串与补0后得到的被除数字符串一个个依次进行“异或”处理(如n=8位),存储在“被除数字符串”中

  5. 如果经过4后得到的“被除数字符串”前面有0则截取后面部分

  6. 如果得到的“被除数字符串”长度大于n=8,则进行4,得到的结果即是所需校验码

(上述算法可以用python轻松实现)

算法之二

字节流

大数据的简化

简化示例

C/C++实现

C代码

Python实现