crc演算法實現
⑴ CRC校驗是怎麼算的
你這個是CRC16要實現校驗的話,你首先需要知道對方採用的是何種CRC公式不同的CRC公式 得到的校驗碼是不一樣的在知道公式的情況下做crc表,然後按照crc演算法,計算這8個位元組的整體crc如果傳輸沒有錯誤的話,最終的crc值是0也可以計算前六個的crc,然後和最後兩個位元組比較,效果是相同的。
⑵ 求一CRC演算法,需要提供思路,最好有現成工具計算。
CRC
代數學的一般性演算法
在代數編碼理論中,將一個碼組表示為一個多項式,碼組中各碼元當作多項式的系數。例如
1100101
表示為
1·x6+1·x5+0·x4+0·x3+1·x2+0·x+1,即
x6+x5+x2+1。
設編碼前的原始信息多項式為P(x),P(x)的最高冪次加1等於k;生成多項式為G(x),G(x)的最高冪次等於r;CRC多項式為R(x);編碼後的帶CRC的信息多項式為T(x)。
發送方編碼方法:將P(x)乘以xr(即對應的二進制碼序列左移r位),再除以G(x),所得余式即為R(x)。用公式表示為
T(x)=xrP(x)+R(x)
接收方解碼方法:將T(x)除以G(x),如果余數為0,則說明傳輸中無錯誤發生,否則說明傳輸有誤。
舉例來說,設信息碼為1100,生成多項式為1011,即P(x)=x3+x2,G(x)=x3+x+1,計算CRC的過程為
xrP(x)
x3(x3+x2)
x6+x5
x
---------
=
------------
=
---------
=
(x3+x2+x)
+
---------
G(x)
x3+x+1
x3+x+1
x3+x+1
即
R(x)=x。注意到G(x)最高冪次r=3,得出CRC為010。
附:CRC演算法的C程序
1)
求CRC碼的運算採用模2運算,
所謂模2運算就是不帶進位和借位,
因此加法和減法等價,實際上就是邏輯上的異或運算,
除法可以用多次模2減法實現.
2)
所謂CRC碼,
就是把數據塊左移16位,
然後除以0x11021所得到的余數(由CCITT推薦).
3)
據此寫出以下的CRC的C程序.
*ptr指向發送數據塊的首地址,
len是數據塊以位元組為單位的長度.
uint
cal_crc(uchar
*ptr,
uchar
len)
{
uint
crc;
uchar
i;
crc=0;
while(len--!=0)
{
for(i=0x80;
i!=0;
i/=2)
{
if((crc&0x8000)!=0)
{crc*=2;
crc^=0x1021;}
else
crc*=2;
if((*ptr&i)!=0)
crc^=0x1021;
}
ptr++;
}
return(crc);
⑶ 關於CRC演算法,高手賜教
循環冗餘校驗(CRC)是一種根據網路數據封包或電腦檔案等數據產生少數固定位數的一種散列函數,主要用來檢測或校驗數據傳輸或者保存後可能出現的錯誤。生成的數字在傳輸或者儲存之前計算出來並且附加到數據後面,然後接收方進行檢驗確定數據是否發生變化。一般來說,循環冗餘校驗的值都是32位的整數。由於本函數易於用二進制的電腦硬體使用、容易進行數學分析並且尤其善於檢測傳輸通道干擾引起的錯誤,因此獲得廣泛應用。它是由W. Wesley Peterson在他1961年發表的論文中披露[1]。
{{noteTA
|T=zh-hans:循環冗餘校驗;zh-hant:循環冗餘校驗;
|1=zh-hans:循環冗餘校驗;zh-hant:循環冗餘校驗;
}}
'''循環冗餘校驗'''(CRC)是一種根據網路數據封包或[[電腦檔案]]等數據產生少數固定位數的一種[[散列函數]],主要用來檢測或校驗數據傳輸或者保存後可能出現的錯誤。生成的數字在傳輸或者儲存之前計算出來並且附加到數據後面,然後接收方進行檢驗確定數據是否發生變化。一般來說,循環冗餘校驗的值都是32位的整數。由於本函數易於用二進制的[[電腦硬體]]使用、容易進行數學分析並且尤其善於檢測傳輸通道干擾引起的錯誤,因此獲得廣泛應用。它是由[[W. Wesley Peterson]]在他1961年發表的論文中披露<ref name="PetersonBrown1961">
{{cite journal
| author = Peterson, W. W. and Brown, D. T.
| year = 1961
| month = January
| title = Cyclic Codes for Error Detection
| journal = Proceedings of the IRE
| doi = 10.1109/JRPROC.1961.287814
| issn = 0096-8390
| volume = 49
| pages = 228
}}</ref>。
==簡介==
CRC「校驗和」是兩個位元數據流採用二進制除法(沒有進位,使用XOR異或來代替減法)相除所得到的余數。其中被除數是需要計算校驗和的信息數據流的二進製表示;除數是一個長度為<math>n+1</math>的預定義(短)的二進制數,通常用多項式的系數來表示。在做除法之前,要在信息數據之後先加上<math>n</math>個0.
CRCa 是基於[[有限域]]GF(2)([[同餘|關於2同餘]])的[[多項式環]]。簡單的來說,就是所有系數都為0或1(又叫做二進制)的多項式系數的集合,並且集合對於所有的代數操作都是封閉的。例如:
:<math>(x^3 + x) + (x + 1) = x^3 + 2x + 1 \equiv x^3 + 1</math>
2會變成0,因為對系數的加法都會模2. 乘法也是類似的:
:<math>(x^2 + x)(x + 1) = x^3 + 2x^2 + x \equiv x^3 + x</math>
我們同樣可以對多項式作除法並且得到商和余數。例如, 如果我們用''x''<sup>3</sup> + ''x''<sup>2</sup> + ''x''除以''x'' + 1。我們會得到:
:<math>\frac{(x^3 + x^2 + x)}{(x+1)} = (x^2 + 1) - \frac{1}{(x+1)}</math>
<!--註:在說「除以」的時候, 讀者將會看到等式中的除號。這里看不到除號常使我感到有點混亂。-->
也就是說,
:<math>(x^3 + x^2 + x) = (x^2 + 1)(x + 1) - 1</math>
這里除法得到了商''x''<sup>2</sup> + 1和余數-1,因為是奇數所以最後一位是1。
字元串中的每一位其實就對應了這樣類型的多項式的系數。為了得到CRC, 我們首先將其乘以<math>x^{n}</math>,這里<math>n</math>是一個固定多項式的[[多項式的階|階]]數, 然後再將其除以這個固定的多項式,余數的系數就是CRC。
在上面的等式中,<math>x^2+x+1</math>表示了本來的信息位是<code>111</code>, <math>x+1</math>是所謂的'''鑰匙''', 而余數<math>1</math>(也就是<math>x^0</math>)就是CRC. key的最高次為1, 所以我們將原來的信息乘上<math>x^1</math>來得到<math>x^3 + x^2 + x</math>,也可視為原來的信息位補1個零成為<code>1110</code>。
一般來說,其形式為:
:<math>M(x) \cdot x^{n} = Q(x) \cdot K(x) + R (x) </math>
這里 M(x) 是原始的信息多項式。K(x)是<math>n</math>階的「鑰匙」多項式。<math>M(x) \cdot x^{n}</math>表示了將原始信息後面加上<math>n</math>個0。R(x)是余數多項式,既是CRC「校驗和」。在通訊中,發送者在原始的信息數據M後加上<math>n</math>位的R(替換本來附加的0)再發送。接收者收到M和R後,檢查<math>M(x) \cdot x^{n} - R(x)</math>是否能被<math>K(x)</math>整除。如果是,那麼接收者認為該信息是正確的。值得注意的是<math>M(x) \cdot x^{n} - R(x)</math>就是發送者所想要發送的數據。這個串又叫做''codeword''.
CRCs 經常被叫做「[[校驗和]]」, 但是這樣的說法嚴格來說並不是准確的,因為技術上來說,校驗「和」是通過加法來計算的,而不是CRC這里的除法。
「[[錯誤糾正編碼]]」常常和CRCs緊密相關,其語序糾正在傳輸過程中所產生的錯誤。這些編碼方式常常和數學原理緊密相關。
==實現==
==變體==
CRC 有幾種不同的變體
* <code>shiftRegister</code> 可以逆向使用,這樣就需要檢測最低位的值,每次向右移動一位。這就要求 <code>polynomial</code> 生成逆向的數據位結果。''實際上這是最常用的一個變體。''
* 可以先將數據最高位讀到移位寄存器,也可以先讀最低位。在通訊協議中,為了保留 CRC 的[[突發錯誤]]檢測特性,通常按照[[物理層]]發送數據位的方式計算 CRC。
* 為了檢查 CRC,需要在全部的碼字上進行 CRC 計算,而不是僅僅計算消息的 CRC 並把它與 CRC 比較。如果結果是 0,那麼就通過這項檢查。這是因為碼字 <math>M(x) \cdot x^{n} - R(x) = Q(x) \cdot K(x)</math> 可以被 <math>K(x)</math> 整除。
* 移位寄存器可以初始化成 1 而不是 0。同樣,在用演算法處理之前,消息的最初 <math>n</math> 個數據位要取反。這是因為未經修改的 CRC 無法區分只有起始 0 的個數不同的兩條消息。而經過這樣的取反過程,CRC 就可以正確地分辨這些消息了。
* CRC 在附加到消息數據流的時候可以進行取反。這樣,CRC 的檢查可以用直接的方法計算消息的 CRC、取反、然後與消息數據流中的 CRC 比較這個過程來完成,也可以通過計算全部的消息來完成。在後一種方法中,正確消息的結果不再是 0,而是 <math>\sum_{i=n}^{2n-1} x^{i}</math> 除以 <math>K(x)</math> 得到的結果。這個結果叫作核驗多項式 <math>C(x)</math>,它的十六進製表示也叫作[[幻數]]。
按照慣例,使用 CRC-32 多項式以及 CRC-16-CCITT 多項式時通常都要取反。CRC-32 的核驗多項式是
<math>C(x) = x^{31} + x^{30} + x^{26} + x^{25} + x^{24} + x^{18} + x^{15} + x^{14} + x^{12} + x^{11} + x^{10} + x^8 + x^6 + x^5 + x^4 + x^3 + x + 1</math>。
==錯誤檢測能力==
CRC 的錯誤檢測能力依賴於關鍵多項式的階次以及所使用的特定關鍵多項式。''誤碼多項式'' <math>E(x)</math> 是接收到的消息碼字與正確消息碼字的''異或''結果。當且僅當誤碼多項式能夠被 CRC 多項式整除的時候 CRC 演算法無法檢查到錯誤。
* 由於 CRC 的計算基於除法,任何多項式都無法檢測出一組全為零的數據出現的錯誤或者前面丟失的零。但是,可以根據 CRC 的[[#變體|變體]]來解決這個問題。
* 所有隻有一個數據位的錯誤都可以被至少有兩個非零系數的任意多項式檢測到。誤碼多項式是 <math>x^k</math>,並且 <math>x^k</math> 只能被 <math>i \le k</math> 的多項式 <math>x^i</math> 整除。
* CRC 可以檢測出所有間隔距離小於[[多項式階次]]的雙位錯誤,在這種情況下的誤碼多項式是
<math>E(x) = x^i + x^k = x^k \cdot (x^{i-k} + 1), \; i > k</math>。
如上所述,<math>x^k</math> 不能被 CRC 多項式整除,它得到一個 <math>x^{i-k} + 1</math> 項。根據定義,滿足多項式整除 <math>x^{i-k} + 1</math> 的 <math>{i-k}</math> 最小值就是多項是的階次。最高階次的多項式是[[本原多項式]],帶有二進制系數的 <math>n</math> 階多項式
==CRC 多項式規范==
下面的表格略去了「初始值」、「反射值」以及「最終異或值」。
* 對於一些復雜的校驗和來說這些十六進制數值是很重要的,如 CRC-32 以及 CRC-64。通常小於 CRC-16 的 CRC 不需要使用這些值。
* 通常可以通過改變這些值來得到各自不同的校驗和,但是校驗和演算法機制並沒有變化。
CRC 標准化問題
* 由於 CRC-12 有三種常用的形式,所以 CRC-12 的定義會有歧義
* 在應用的 CRC-8 的兩種形式都有數學上的缺陷。
* 據稱 CRC-16 與 CRC-32 至少有 10 種形式,但沒有一種在數學上是最優的。
* 同樣大小的 CCITT CRC 與 ITU CRC 不同,這個機構在不同時期定義了不同的校驗和。
==常用 CRC(按照 ITU-IEEE 規范)==
{|class="wikitable"
! 名稱|| 多項式 || 表示法:正常或者翻轉
|-
|CRC-1 || <math>x + 1</math><br>(用途:硬體,也稱為[[奇偶校驗位]]) || 0x1 or 0x1 (0x1)
|-
|CRC-5-CCITT || <math>x^{5} + x^{3} + x + 1</math> ([[ITU]] G.704 標准) || 0x15 (0x??)
|-
|CRC-5-USB || <math>x^{5} + x^{2} + 1</math> (用途:[[USB]] 信令包) || 0x05 or 0x14 (0x9)
|-
|CRC-7 || <math>x^{7} + x^{3} + 1</math> (用途:通信系統) || 0x09 or 0x48 (0x11)
|-
|CRC-8-ATM || <math>x^8 + x^2 + x + 1</math> (用途:ATM HEC) || 0x07 or 0xE0 (0xC1)
|-
|CRC-8-[[CCITT]] || <math>x^8 + x^7 + x^3 + x^2 + 1</math> (用途:[[1-Wire]] [[匯流排]]) ||
|-
|CRC-8-[[Dallas_Semiconctor|Dallas]]/[[Maxim_IC|Maxim]] || <math>x^8 + x^5 + x^4 + 1</math> (用途:[[1-Wire]] [[bus]]) || 0x31 or 0x8C
|-
|CRC-8 || <math>x^8 + x^7 + x^6 + x^4 + x^2 +1</math> || 0xEA(0x??)
|-
|CRC-10 || x<sup>10</sup> + x<sup>9</sup> + x<sup>5</sup> + x<sup>4</sup> + x + 1 || 0x233 (0x????)
|-
|CRC-12 || <math>x^{12} + x^{11} + x^3 + x^2 + x + 1</math><br>(用途:通信系統) || 0x80F or 0xF01 (0xE03)
|-
|CRC-16-Fletcher || 參見 [[Fletcher's checksum]] || 用於 [[Adler-32]] A & B CRC
|-
|CRC-16-CCITT || ''x''<sup>16</sup> + ''x''<sup>12</sup> + ''x''<sup>5</sup> + 1 ([[X25]], [[V.41]], [[Bluetooth]], [[PPP]], [[IrDA]]) || 0x1021 or 0x8408 (0x0811)
|-
|CRC-16-[[IBM]] || ''x''<sup>16</sup> +''x''<sup>15</sup> + ''x''<sup>2</sup> + 1 || 0x8005 or 0xA001 (0x4003)
|-
|CRC-16-[[BBS]] || x<sup>16</sup> + x<sup>15</sup> + x<sup>10</sup> + x<sup>3</sup> (用途:[[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]] || <math>x^{32} + x^{26} + x^{23} + x^{22} + x^{16} + x^{12} + x^{11} + x^{10} + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1</math> || 0x04C11DB7 or 0xEDB88320 (0xDB710641)
|-
|CRC-32C (Castagnoli)<ref name="cast93"/>|| <math>x^{32} + x^{28} + x^{27} + x^{26} + x^{25} + x^{23} + x^{22} + x^{20} + x^{19} + x^{18} + x^{14} + x^{13} + x^{11} + x^{10} + x^9 + x^8 + x^6 + 1</math> || 0x1EDC6F41 or 0x82F63B78 (0x05EC76F1)
|-
|CRC-64-ISO || <math>x^{64} + x^4 + x^3 + x + 1</math><br>(use: ISO 3309) || 0x000000000000001B or 0xD800000000000000 (0xB000000000000001)
|-
|CRC-64-[[Ecma International|ECMA]]-182 || <math>x^{64} + x^{62} + x^{57} + x^{55} + x^{54} + x^{53} + x^{52} + x^{47} + x^{46} + x^{45} + x^{40} + x^{39} + x^{38} + x^{37} + x^{35} + x^{33} + x^{32} </math><br><!--Too long to display in one table--><math>+ x^{31} + x^{29} + x^{27} + x^{24} + x^{23} + x^{22} + x^{21} + x^{19} + x^{17} + x^{13} + x^{12} + x^{10} + x^9 + x^7 + x^4 + x + 1</math><br>(as described in [http://www.ecma-international.org/publications/standards/Ecma-182.htm ECMA-182] p.63) || 0x42F0E1EBA9EA3693 or 0xC96C5795D7870F42 (0x92D8AF2BAF0E1E85)
|-
|CRC-128 || IEEE-ITU 標准。被 [[MD5]] & [[SHA-1]] 取代||
|-
|CRC-160 || IEEE-ITU 標准。被 [[MD5]] & [[SHA-1]] 取代||
|-
|}
==CRC 與數據完整性==
盡管在[[錯誤檢測]]中非常有用,CRC 並不能可靠地驗證[[數據完整性]](即數據沒有發生任何變化),這是因為 CRC 多項式是線性結構,可以非常容易地''故意''改變數據而維持 CRC 不變,參見[http://www.woodmann.com/fravia/crctut1.htm CRC and how to Reverse it]中的證明。我們可以用 [[Message authentication code]] 驗證數據完整性。
===CRC發生碰撞的情況===
與所有其它的[[散列函數]]一樣,在一定次數的碰撞測試之後 CRC 也會接近 100% 出現碰撞。CRC 中每增加一個數據位,就會將碰撞數目減少接近 50%,如 CRC-20 與 CRC-21 相比。
* 理論上來講,CRC64 的碰撞概率大約是每 18{{e|18}} 個 CRC 碼出現一次。
* 由於 CRC 的不分解多項式特性,所以經過合理設計的較少位數的 CRC 可能會與使用較多數據位但是設計很差的 CRC 的效率相媲美。在這種情況下 CRC-32 幾乎同 CRC-40 一樣優秀。
===設計 CRC 多項式===
生成多項式的選擇是 CRC 演算法實現中最重要的部分,所選擇的多項式必須有最大的錯誤檢測能力,同時保證總體的碰撞概率最小。多項式最重要的屬性是它的長度,也就是最高非零系數的數值,因為它直接影響著計算的校驗和的長度。
最常用的多項式長度有
* 9 位 (CRC-8)
* 17 位 (CRC-16)
* 33 位 (CRC-32)
* 65 位 (CRC-64)
在構建一個新的 CRC 多項式或者改進現有的 CRC 時,一個通用的數學原則是使用滿足所有模運算不可分解多項式約束條件的多項式。
* 這種情況下的不可分解是指多項式除了 1 與它自身之外不能被任何其它的多項式整除。
生成多項式的特性可以從演算法的定義中推導出來:
* 如果 CRC 有多於一個的非零系數,那麼 CRC 能夠檢查出輸入消息中的所有單數據位錯誤。
* CRC 可以用於檢測短於 2k 的輸入消息中的所有雙位錯誤,其中 k 是多項式的最長的不可分解部分的長度。
* 如果多項式可以被 x+1 整除,那麼不存在可以被它整除的有奇數個非零系數的多項式。因此,它可以用來檢測輸入消息中的奇數個錯誤,就象奇偶校驗函數那樣。
==參見==
總的分類
* [[糾錯碼]]
* [[校驗和演算法列表]]
* [[奇偶校驗位]]
特殊技術參考
* [[Adler-32]]
* [[Fletcher's checksum]]
==參考文獻 ==
<references/>
==外部鏈接==
* [http://www.relisoft.com/science/CrcMath.html Tutorial and C++ implementation] of CRC
* Cyclic rendancy check - a simple guide to what it means for your data, CD and DVD discs. http://www.softwarepatch.com/tips/cyclic-rendancy.html
* [http://www.ross.net/crc/ ''The CRC Pitstop'']
* Williams, R. (1993-09) [http://www.repairfaq.org/filipg/LINK/F_crc_v3.html ''A Painless Guide to CRC Error Detection Algorithms'']
* [http://www.4d.com/docs/CMU/CMU79909.HTM ''Understanding Cyclic Rendancy Check'']
* Black, R. (1994-02) [http://www.cl.cam.ac.uk/Research/SRG/bluebook/21/crc/crc.html ''Fast CRC32 in Software''] — Algorithm 4 is used in Linux and info-zip's zip and unzip.
* Barr, M. ([http://www.netrino.com/Connecting/1999-11/ ''1999-11''], [http://www.netrino.com/Connecting/1999-12/ ''1999-12''], [http://www.netrino.com/Connecting/2000-01/ ''2000-01'']) checksums, CRCs, and their source code. Embedded Systems Programming
* [http://www.codeproject.com/cpp/crc32.asp CRC32: Generating a checksum for a file], C++ implementation by Brian Friesen
* Online [http://serversniff.net/hash.php Tool to compute common CRCs (8/16/32/64) from strings]
* Online [http://www.zorc.breitbandkatze.de/crc.html CRC calculator]
* Online [http://www.easics.com/webtools/crctool CRC Tool: Generator of synthesizable CRC functions]
* [http://www.paulschou.com/tools/xlate/ Online Char (ASCII), HEX, Binary, Base64, etc... Encoder/Decoder with MD2, MD4, MD5, SHA1+2, CRC, etc. hashing algorithms]
* [http://apollo.backplane.com/matt/crc64.html CRC16 to CRC64 collision research]
* [http://sar.informatik.hu-berlin.de/research/publications/index.htm#SAR-PR-2006-05 Reversing CRC – Theory and Practice.]
{{math-stub}}
[[Category:校驗和演算法]]
[[bg:CRC]]
[[ca:Control de rendància cíclica]]
[[cs:Cyklický rendantní součet]]
[[de:Zyklische Rendanzprüfung]]
[[en:Cyclic rendancy check]]
[[es:Control de rendancia cíclica]]
[[eu:CRC]]
[[fi:CRC]]
[[fr:Contrôle de redondance cyclique]]
[[he:בדיקת יתירות מחזורית]]
[[id:CRC]]
[[it:Cyclic rendancy check]]
[[ja:巡迴冗長検査]]
[[ko:순환 중복 검사]]
[[nl:Cyclic Rendancy Check]]
[[pl:CRC]]
[[pt:CRC]]
[[ru:Циклический избыточный код]]
[[simple:Cyclic rendancy check]]
[[sk:Kontrola cyklickým kódom]]
[[sv:Cyclic Rendancy Check]]
[[vi:CRC]]
⑷ 關於CRC效驗
為保證傳輸過程的正確性,需要對通信過程進行差錯控制。差錯控制最常用的方法是自動請求重發方式(ARQ)、向前糾錯方式(FEC)和混合糾錯(HEC)。在傳輸過程誤碼率比較低時,用FEC方式比較理想。在傳輸過程誤碼率較高時,採用FEC容易出現「亂糾」現象。HEC方式則是ARQ和FEC的結合。在許多數字通信中,廣泛採用ARQ方式,此時的差錯控制只需要檢錯功能。實現檢錯功能的差錯控制方法很多,傳統的有:奇偶校驗、校驗和檢測、重復碼校驗、恆比碼校驗、行列冗餘碼校驗等,這些方法都是增加數據的冗餘量,將校驗碼和數據一起發送到接受端。接受端對接受到的數據進行相同校驗,再將得到的校驗碼和接受到的校驗碼比較,如果二者一致則認為傳輸正確。但這些方法都有各自的缺點,誤判的概率比較高。
循環冗餘校驗CRC(Cyclic Rendancy Check)是由分組線性碼的分支而來,其主要應用是二元碼組。編碼簡單且誤判概率很低,在通信系統中得到了廣泛的應用。下面重點介紹了CRC校驗的原理及其演算法實現。
CRC校驗可以100%地檢測出所有奇數個隨機錯誤和長度小於等於k(k為g(x)的階數)的突發錯誤。所以CRC的生成多項式的階數越高,那麼誤判的概率就越小。
CRC代碼的一些基本概念和運算:
CRC多項式:
例:
代碼:1010111 對應的多項式為:X6+X4+X2+X+1
多項式X5+X3+X2+X1+1對應的代碼為101111
CRC生成多項式:
首位和最後一位必須是1。CRC生成多項式是給定的,在傳輸過程中不變,即發送和接收端生成碼相同。
一些常用的校驗碼為:
CRC8=X8+X5+X4+1
CRC-CCITT=X16+X12+X5+1
CRC16=X16+X15+X5+1
CRC12=X12+X11+X3+X2+1
CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1
CRC的運算本質是異或運算(模2除法)
例:原信息碼為1011001
生成碼為11001
校驗碼計算過程
① 將信息碼左移4位(生成碼長-1);得到10110010000
② 異或運算
10110010000
11001
01111010000(前面的數進行異或運算,後面的直接抄下來)
11001
0011110000(和生成碼異或運算的必須從1開始)
11001
00111000
11001
001010
這樣得到的結果為1010,即為所需要的校驗碼,添加到信息碼後,得到發送的代碼為:
10110011010
我把上面的手算過程用c#寫了一段程序,如下:
using System;
namespace mainClass
{
public class mainProgress
{
public static void Main()
{
byte[] msg={1,0,1,1,0,0,1};//信息碼
byte[] gmsg=new byte[msg.Length+4];
crc c = new crc();
gmsg=c.code(msg);
Console.Write("編碼後字元串為:");
for (int i = 0; i < gmsg.Length; i++)
{
Console.Write("{0}", gmsg[i].ToString());
}
Console.Write("\n");
byte[] gmsg1={ 1, 0, 1, 1, 0, 1, 1 };//接收到的代碼
bool r = c.det(gmsg1);
if (r)
{
Console.WriteLine("傳輸正確");
}
else
{ Console.WriteLine("傳輸錯誤"); }
}
}
public class crc//CRC編碼類
{
private byte[] g = { 1,1,0,0,1};//生成碼
public byte[] code(byte[] msg)//編碼
{
byte[] gmsg=new byte[g.Length+msg.Length-1];
msg.CopyTo(gmsg, 0);//
for (int i = 0; i < msg.Length; i++)//完成異或運算,即模2除法
{
if (gmsg[i] == 1)
{
for (int j = 0; j < g.Length; j++)
{
if (gmsg[i + j] == g[j])
gmsg[i + j] = 0;
else
gmsg[i + j] = 1;
}
}
}
msg.CopyTo(gmsg, 0);
return gmsg;
}
private bool f=true;
//接收端檢測
public bool det(byte[] gmsg)
{
for (int i = 0; i < gmsg.Length - g.Length+1; i++)
{
if(gmsg[i]==0)
continue;
for (int j = 0; j < g.Length; j++)
{
if (gmsg[i + j] == g[j])
gmsg[i + j] = 0;
else
gmsg[i + j] = 1;
}
}
for (int i = 0; i < gmsg.Length; i++)
{
if (gmsg[i] == 1)
f = false;
}
return f;
}
}
}
⑸ CRC32的計算方法
CRC的本質是模-2除法的余數,採用的除數不同,CRC的類型也就不一樣。通常,CRC的除數用生成多項式來表示。 最常用的CRC碼及生成多項式名稱生成多項式。
CRC-12:
(5)crc演算法實現擴展閱讀
通常的CRC演算法在計算一個數據段的CRC值時,其CRC值是由求解每個數值的CRC值的和對CRC寄存器的值反復更新而得到的。這樣,求解CRC的速度較慢。通過對CRC演算法的研究,我們發現:一個8位數據加到16位累加器中去,只有累加器的高8位或低8位與數據相作用,其結果僅有256種可能的組合值。
因而,我們可以用查表法來代替反復的運算,這也同樣適用於CRC32的計算。本文所提供的程序庫中,函數crchware是一般的16位CRC的演算法。mk-crctbl用以在內存中建立一個CRC數值表。
⑹ java中CRC演算法是個什麼東東
CRC校驗碼的基本思想是利用線性編碼理論,在發送端根據要傳送的k位二進制碼序列,以一定的規則產生一個校驗用的監督碼(既CRC碼)r位,並附在信息後邊,構成一個新的二進制碼序列數共(k+r)位,最後發送出去。在接收端,則根據信息碼和CRC碼之間所遵循的規則進行檢驗,以確定傳送中是否出錯。
在數據存儲和數據通訊領域,CRC無處不在:著名的通訊協議X.25的FCS(幀檢錯序列)採用的是CRC. CCITT,ARJ、LHA等壓縮工具軟體採用的是CRC32,磁碟驅動器的讀寫採用了CRC16,通用的圖像存儲格式GIF、TIFF等也都用CRC作為檢錯手段。
CRC的本質是模-2除法的余數,採用的除數不同,CRC的類型也就不一樣。通常,CRC的除數用生成多項式來表示。最常用的CRC碼的生成多項式有CRC16,CRC32.
以CRC16為例,16位的CRC碼產生的規則是先將要發送的二進制序列數左移16位(既乘以2^16)後,再除以一個多項式,最後所得到的余數既是CRC碼,如下式所示,其中K(X)表示n位的二進制序列數,G(X)為多項式,Q(X)為整數,R(X)是余數(既CRC碼)。
K(X)>>16=G(x)Q(x)+R(x)
求CRC碼所採用模2加減運演算法則,既是不帶進位和借位的按位加減,這種加減運算實際上就是邏輯上的異或運算,加法和減法等價,乘法和除法運算與普通代數式的乘除法運算是一樣,符合同樣的規律。生成CRC碼的多項式如下,其中CRC-16和CRC-CCITT產生16位的CRC碼,而CRC-32則產生的是32位的CRC碼
接收方將接收到的二進制序列數(包括信息碼和CRC碼)除以多項式,如果余數為0,則說明傳輸中無錯誤發生,否則說明傳輸有誤,關於其原理這里不再多述。用軟體計算CRC碼時,接收方可以將接收到的信息碼求CRC碼,比較結果和接收到的CRC碼是否相同。
CCITT推薦的高級數據鏈路控制規程HDLC的幀校驗序列FCS中,使用CCITT-16即CRC16,其生成多項式為G(x)=x16+x12+x5+1,CRC-32的生成多項式為G(x)=x32+x26+x23+x22+x16+x11+x10+x16+x8+x7+x5+x4+x2+x+1
⑺ CRC校驗的演算法
在代數編碼理論中,將一個碼組表示為一個多項式,碼組中各碼元當作多項式的系數。例如 1100101 表示為1·x6+1·x5+0·x4+0·x3+1·x2+0·x+1,即 x6+x5+x2+1。
設編碼前的原始信息多項式為P(x),P(x)的最高冪次加1等於k;生成多項式為G(x),G(x)的最高冪次等於r;CRC多項式為R(x);編碼後的帶CRC的信息多項式為T(x)。
發送方編碼方法:將P(x)乘以xr(即對應的二進制碼序列左移r位),再除以G(x),所得余式即為R(x)。用公式表示為T(x)=xrP(x)+R(x)
接收方解碼方法:將T(x)除以G(x),得到一個數,如果這個余數為0,則說明傳輸中無錯誤發生,否則說明傳輸有誤。
舉例來說,設信息編碼為1100,生成多項式為1011,即P(x)=x3+x2,G(x)=x3+x+1,計算CRC的過程為
xrP(x) =x3(x3+x2) = x6+x5 G(x)= x3+x+1 即 R(x)=x。注意到G(x)最高冪次r=3,得出CRC為010。
如果用豎式除法(計算機的模二,計算過程為
1110 ------- 1011 /1100000 (1100左移3位) 1011 ---- 1110 1011 ----- 1010 1011 ----- 0010 0000 ---- 010 因此,T(x)=(x6+x5)+(x)=x6+x5+x, 即 1100000+010=1100010
如果傳輸無誤,
T(x)= (x6+x5+x)/G(x) = , G(x)= 無余式。回頭看一下上面的豎式除法,如果被除數是1100010,顯然在商第三個1時,就能除盡。
上述推算過程,有助於我們理解CRC的概念。但直接編程來實現上面的演算法,不僅繁瑣,效率也不高。實際上在工程中不會直接這樣去計算和驗證CRC。
下表中列出了一些見於標準的CRC資料:
名稱 生成多項式 簡記式* 應用舉例
CRC-4 x4+x+1 3 ITU G.704
CRC-8 x8+x5+x4+1 31 DS18B20
CRC-12 x12+x11+x3+x2+x+1 80F
CRC-16 x16+x15+x2+1 8005 IBM SDLC
CRC-ITU** x16+x12+x5+1 1021 ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS,ZigBee
CRC-32 x32+x26+x23+...+x2+x+1 04C11DB7 ZIP, RAR, IEEE 802 LAN/FDDI,IEEE 1394,PPP-FCS
CRC-32c x32+x28+x27+...+x8+x6+1 1EDC6F41 SCTP
* 生成多項式的最高冪次項系數是固定的1,故在簡記式中,將最高的1統一去掉了,如04C11DB7實際上是104C11DB7。 ** 前稱CRC-CCITT。ITU的前身是CCITT。
備註:
(1)生成多項式是標准規定的
(2)CRC校驗碼是基於將位串看作是系數為0或1的多項式,一個k位的數據流可以看作是關於x的從k-1階到0階的k-1次多項式的系數序列。採用此編碼,發送方和接收方必須事先商定一個生成多項式G(x),其高位和低位必須是1。要計算m位的幀M(x)的校驗和,基本思想是將校驗和加在幀的末尾,使這個帶校驗和的幀的多項式能被G(x)除盡。當接收方收到加有校驗和的幀時,用G(x)去除它,如果有餘數,則CRC校驗錯誤,只有沒有餘數的校驗才是正確的。
⑻ crc演算法在單片機上的實現
CRC演算法原理及C語言實現
摘 要 本文從理論上推導出CRC演算法實現原理,給出三種分別適應不同計算機或微控制器硬體環境的C語言程序。讀者更能根據本演算法原理,用不同的語言編寫出獨特風格更加實用的CRC計算程序。
關鍵詞 CRC 演算法 C語言
1 引言
循環冗餘碼CRC檢驗技術廣泛應用於測控及通信領域。CRC計算可以靠專用的硬體來實現,但是對於低成本的微控制器系統,在沒有硬體支持下實現CRC檢驗,關鍵的問題就是如何通過軟體來完成CRC計算,也就是CRC演算法的問題。
這里將提供三種演算法,它們稍有不同,一種適用於程序空間十分苛刻但CRC計算速度要求不高的微控制器系統,另一種適用於程序空間較大且CRC計算速度要求較高的計算機或微控制器系統,最後一種是適用於程序空間不太大,且CRC計算速度又不可以太慢的微控制器系統。
2 CRC簡介
CRC校驗的基本思想是利用線性編碼理論,在發送端根據要傳送的k位二進制碼序列,以一定的規則產生一個校驗用的監督碼(既CRC碼)r位,並附在信息後邊,構成一個新的二進制碼序列數共(k+r)位,最後發送出去。在接收端,則根據信息碼和CRC碼之間所遵循的規則進行檢驗,以確定傳送中是否出錯。
16位的CRC碼產生的規則是先將要發送的二進制序列數左移16位(既乘以 )後,再除以一個多項式,最後所得到的余數既是CRC碼,如式(2-1)式所示,其中B(X)表示n位的二進制序列數,G(X)為多項式,Q(X)為整數,R(X)是余數(既CRC碼)。
(2-1)
求CRC碼所採用模2加減運演算法則,既是不帶進位和借位的按位加減,這種加減運算實際上就是邏輯上的異或運算,加法和減法等價,乘法和除法運算與普通代數式的乘除法運算是一樣,符合同樣的規律。生成CRC碼的多項式如下,其中CRC-16和CRC-CCITT產生16位的CRC碼,而CRC-32則產生的是32位的CRC碼。本文不討論32位的CRC演算法,有興趣的朋友可以根據本文的思路自己去推導計算方法。
CRC-16:(美國二進制同步系統中採用)
CRC-CCITT:(由歐洲CCITT推薦)
CRC-32:
接收方將接收到的二進制序列數(包括信息碼和CRC碼)除以多項式,如果余數為0,則說明傳輸中無錯誤發生,否則說明傳輸有誤,關於其原理這里不再多述。用軟體計算CRC碼時,接收方可以將接收到的信息碼求CRC碼,比較結果和接收到的CRC碼是否相同。
3 按位計算CRC
對於一個二進制序列數可以表示為式(3-1):
(3-1)
求此二進制序列數的CRC碼時,先乘以 後(既左移16位),再除以多項式G(X),所得的余數既是所要求的CRC碼。如式(3-2)所示:
(3-2)
可以設: (3-3)
其中 為整數, 為16位二進制余數。將式(3-3)代入式(3-2)得:
(3-4)
再設: (3-5)
其中 為整數, 為16位二進制余數,將式(3-5)代入式(3-4),如上類推,最後得到:
(3-6)
根據CRC的定義,很顯然,十六位二進制數 既是我們要求的CRC碼。
式(3-5)是編程計算CRC的關鍵,它說明計算本位後的CRC碼等於上一位CRC碼乘以2後除以多項式,所得的余數再加上本位值除以多項式所得的余數。由此不難理解下面求CRC碼的C語言程序。*ptr指向發送緩沖區的首位元組,len是要發送的總位元組數,0x1021與多項式有關。
unsigned int cal_crc(unsigned char *ptr, unsigned char len) {
unsigned char i;
unsigned int crc=0;
while(len--!=0) {
for(i=0x80; i!=0; i/=2) {
if((crc&;0x8000)!=0) {crc*=2; crc^=0x1021;} /* 余式CRC乘以2再求CRC */
else crc*=2;
if((*ptr&;i)!=0) crc^=0x1021; /* 再加上本位的CRC */
}
ptr++;
}
return(crc);
}
按位計算CRC雖然代碼簡單,所佔用的內存比較少,但其最大的缺點就是一位一位地計算會佔用很多的處理器處理時間,尤其在高速通訊的場合,這個缺點更是不可容忍。因此下面再介紹一種按位元組查錶快速計算CRC的方法。
4 按位元組計算CRC
不難理解,對於一個二進制序列數可以按位元組表示為式(4-1),其中 為一個位元組(共8位)。
(4-1)
求此二進制序列數的CRC碼時,先乘以 後(既左移16位),再除以多項式G(X),所得的余數既是所要求的CRC碼。如式(4-2)所示:
(4-2)
可以設: (4-3)
其中 為整數, 為16位二進制余數。將式(4-3)代入式(4-2)得:
(4-4)
因為:
(4-5)
其中 是 的高八位, 是 的低八位。將式(4-5)代入式(4-4),經整理後得:
(4-6)
再設: (4-7)
其中 為整數, 為16位二進制余數。將式(4-7)代入式(4-6),如上類推,最後得:
(4-8)
很顯然,十六位二進制數 既是我們要求的CRC碼。
式(4-7)是編寫按位元組計算CRC程序的關鍵,它說明計算本位元組後的CRC碼等於上一位元組余式CRC碼的低8位左移8位後,再加上上一位元組CRC右移8位(也既取高8位)和本位元組之和後所求得的CRC碼,如果我們把8位二進制序列數的CRC全部計算出來,放如一個表裡,採用查表法,可以大大提高計算速度。由此不難理解下面按位元組求CRC碼的C語言程序。*ptr指向發送緩沖區的首位元組,len是要發送的總位元組數,CRC余式表是按0x11021多項式求出的。
unsigned int cal_crc(unsigned char *ptr, unsigned char len) {
unsigned int crc;
unsigned char da;
unsigned int crc_ta[256]={ /* CRC余式表 */
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x 1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
crc=0;
while(len--!=0) {
da=(uchar) (crc/256); /* 以8位二進制數的形式暫存CRC的高8位 */
crc<<=8; /* 左移8位,相當於CRC的低8位乘以 */
crc^=crc_ta[da^*ptr]; /* 高8位和當前位元組相加後再查表求CRC ,再加上以前的CRC */
ptr++;
}
return(crc);
}
很顯然,按位元組求CRC時,由於採用了查表法,大大提高了計算速度。但對於廣泛運用的8位微處理器,代碼空間有限,對於要求256個CRC余式表(共512位元組的內存)已經顯得捉襟見肘了,但CRC的計算速度又不可以太慢,因此再介紹下面一種按半位元組求CRC的演算法。
5 按半位元組計算CRC
同樣道理,對於一個二進制序列數可以按位元組表示為式(5-1),其中 為半個位元組(共4位)。
(5-1)
求此二進制序列數的CRC碼時,先乘以 後(既左移16位),再除以多項式G(X),所得的余數既是所要求的CRC碼。如式(4-2)所示:
(5-2)
可以設: (5-3)
其中 為整數, 為16位二進制余數。將式(5-3)代入式(5-2)得:
(5-4)
因為:
(5-5)
其中 是 的高4位, 是 的低12位。將式(5-5)代入式(5-4),經整理後得:
(5-6)
再設: (5-7)
其中 為整數, 為16位二進制余數。將式(5-7)代入式(5-6),如上類推,最後得:
(5-8)
很顯然,十六位二進制數 既是我們要求的CRC碼。
式(5-7)是編寫按位元組計算CRC程序的關鍵,它說明計算本位元組後的CRC碼等於上一位元組CRC碼的低12位左移4位後,再加上上一位元組余式CRC右移4位(也既取高4位)和本位元組之和後所求得的CRC碼,如果我們把4位二進制序列數的CRC全部計算出來,放在一個表裡,採用查表法,每個位元組算兩次(半位元組算一次),可以在速度和內存空間取得均衡。由此不難理解下面按半位元組求CRC碼的C語言程序。*ptr指向發送緩沖區的首位元組,len是要發送的總位元組數,CRC余式表是按0x11021多項式求出的。
unsigned cal_crc(unsigned char *ptr, unsigned char len) {
unsigned int crc;
unsigned char da;
unsigned int crc_ta[16]={ /* CRC余式表 */
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
}
crc=0;
while(len--!=0) {
da=((uchar)(crc/256))/16; /* 暫存CRC的高四位 */
crc<<=4; /* CRC右移4位,相當於取CRC的低12位)*/
crc^=crc_ta[da^(*ptr/16)]; /* CRC的高4位和本位元組的前半位元組相加後查表計算CRC,
然後加上上一次CRC的余數 */
da=((uchar)(crc/256))/16; /* 暫存CRC的高4位 */
crc<<=4; /* CRC右移4位, 相當於CRC的低12位) */
crc^=crc_ta[da^(*ptr&;0x0f)]; /* CRC的高4位和本位元組的後半位元組相加後查表計算CRC,
然後再加上上一次CRC的余數 */
ptr++;
}
return(crc);
}