CRC32演算法詳細推導(1)

2021-06-22 19:35:05 字數 4081 閱讀 8011

from: 

作為blog再次發出來,詳細描述一下crc32演算法的推導過程。

crc 演算法的數學基礎就不再多囉嗦了,到處都是,簡單提一下。它是以 gf(2) 多項式算術為數學基礎的,gf(2) 多項式中只有乙個變數 x ,其係數也只有 0 和 1 ,比如:

1 *x^6 + 0*x^5 + 1*x^4 + 0*x^3 + 0*x^2 +1*x^1 + 1*x^0

= x^6 + x^4 + x + 1

加減運算不考慮進製和退位。說白了就是下面的運算規則:

0 + 0 = 0    0 - 0 = 0

0 + 1 = 1    0 - 1 = 1

1 + 0 = 1    1 - 0 = 1

1 + 1 = 0    1 - 1 = 0

看看這個規則,其實就是乙個異或運算。

每個生成多項式的係數只能是 0 或 1 ,因此我們可以把它轉化為二進位制形式表示, 比如

g(x)=x^4 + x + 1

,那麼g(x)

對應的二進位制形式就是

10011

, 於是我們就把 gf(2) 多項式的除法轉換成了二進位制形式,和普通除法沒有區別,只是加減運算沒有進製和退位。

比如基於上述規則計算 11010/1001 ,那麼商是 11 ,餘數就是 101 ,簡單吧。

採用 crc 校驗時,傳送方和接收方用同乙個生成多項式 g(x) , g(x) 是乙個 gf(2) 多項式,並且 g(x) 的首位和最後一位的係數必須為 1 。

crc 的處理方法是:傳送方用傳送資料的二進位制多項式 t(x) 除以 g(x) ,得到餘數 y(x) 作為 crc 校驗碼。校驗時,以計算的校正結果是否為 0 為據,判斷資料幀是否出錯。設生成多項式是 r 階的(最高位是 x^r )具體步驟如下面的描述。

傳送方:

1 )在傳送的 m 位資料的二進位制多項式 t(x) 後新增 r 個 0 ,擴張到 m+ r 位,以容納 r 位的校驗碼,追加 0 後的二進位制多項式為  t(x) ;

2 )用 t(x) 除以生成多項式 g(x) ,得到 r 位的餘數 y(x) ,它就是 crc 校驗碼;

3 )把 y(x) 追加到 t(x) 後面,此時的資料 s(x) 就是包含了 crc 校驗碼的待傳送字串;由於 s(x) = t(x) y(x) ,因此 s(x) 肯定能被 g(x) 除盡。

接收方:

1 )接收資料 n(x) ,這個 n(x) 就是包含了 crc 校驗碼的 m+r 位資料;

2 )計算 n(x) 除以 g(x) ,如果餘數為 0 則表示傳輸過程沒有錯誤,否則表示有錯誤。從 n(x) 去掉尾部的 r 位資料,得到的就是原始資料。

生成多項式可不是隨意選擇的,數學上的東西就免了,以下是一些標準的 crc 演算法的生成多項式:

標準生成多項式

16 進製表示

crc12

x^12 + x^11 + x^3 + x^2 + x + 1

0x80f

crc16

x^16 + x^15 + x^2 + 1

0x8005

crc16-ccitt

x^16 + x^12 + x^5 + 1

0x1021

crc32

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

0x04c11db7

根據多項式除法,我們就可以得到原始的 crc 校驗演算法。假設生成多項式 g(x)是r

階的,原始資料存放在

data

中,長度為

len個

bit,

reg是

r+1位的變數。 以 crc-4 為例,生成多項式 g(x)=x^4 + x + 1

,對應了乙個

5bits

的二進位制數字

10011

,那麼reg

就是 5 bits 。

reg[1]

表明reg

的最低位,

reg[r+1]

是reg

的最高位。

通過反覆的移位和進行除法,那麼最終該暫存器中的值去掉最高一位就是我們所要求的餘數。所以可以將上述步驟用下面的流程描述:

[cpp]view plain

copy

reg = 0;  

data = data追加r個;  

pos = 1;  

while(pos <= len)  

// 移出最高位,移入新資料

reg = (reg<<1) | (data[pos]);  

pos++;  

}  return reg; 

// reg中的後r位儲存的就是餘數

由於最後只需要

r位的餘數,所以我們可以嘗試構造乙個r位的

reg,初值為

0,資料

data

依次移入

reg[1]

,同時把

reg[r]

移出reg。

根據上面的演算法可以知道,只有當移出的資料為1時,

reg才和

g(x)

進行xor

運算;於是可以使用下面的演算法:

[cpp]view plain

copy

reg = 0;  

data = data追加r個;  

pos = 1;  

while(pos 

pos++;  

}  return reg; 

// reg中儲存的就是餘數

這種演算法簡單,容易實現,對任意長度生成多項式的 g ( x )都適用,對應的 crc-32 的實現就是:

[cpp]view plain

copy

// 以4 byte資料為例

#define poly 0x04c11db7l // crc32生成多項式

unsigned int crc32_1(unsigned 

int data)  

return reg;  

}  但是如果傳送的資料塊很長的話,這種方法就不太適合了。它一次只能處理乙個 bit 的資料,效率太低。考慮能不能每次處理乙個 byte 的資料呢?事實上這也是當前的 crc-32 實現採用的方法。

這一步驟是通往基於校驗表方法的橋梁,讓我們一步一步來分析上面逐 bit 的運算方式,我們把 reg 和 g(x) 都採用 bit 的方式表示如下:    

考慮把上面逐 bit 的演算法執行 8 次,如果某次移出的不是 1 ,那麼 reg 不會和 g(x) 執行 xor 運算,事實上這相當於將 reg 和 0 執行了 xor 運算。執行過程如下所示,根據 hi-bit 的值,這裡的 g 可能是 g(x) 也可能是 0 。

從上面的執行過程清楚的看到,執行 8 次後, old-reg 的高 8bit 被完全移出, new-reg 就是 old-reg 的低24bit 和資料 data 新移入的 8bit 和 g 一次次執行 xor 運算所得到的。

xor 運算滿足結合律,那就是: a xor b xor c = a xor (b xor c) ,於是我們可以考慮把上面的運算分成兩步進行:

1 )先執行 r 高 8bit 與 g 之間的 xor 運算,將計算結果存入 x 中,如下面的過程所示。

2 )將 r 左移 8bit ,並移入 8bit 的資料,得到的值就是

根據 xor 運算的結合率,最後的結果就等於上面逐 bit 的演算法執行 8 次後的結果,根據這個分解,我們可以修改逐bit 的方式,寫出下面的演算法。

[cpp]view plain

copy

// 以4 byte資料為例

#define poly 0x04c11db7l // crc32生成多項式

unsigned int crc32_2(unsigned 

int data)  

// 計算步驟2

reg = (reg<<8)|p[i];  

reg = reg ^ sum_poly;  

}  return reg;  

}  

CRC32演算法詳細推導(3)

看起來我們已經得到 crc 32 演算法的最終形式了,可是 可是在實際的應用中,資料傳輸時是低位先行的 對於乙個位元組 byte 來講,傳輸將是按照 b1,b2,b8 的順序。而我們上面的演算法是按照高位在前的約定,不管是 reg還是 g x g32,g31,g1 b8,b7,b1 r32,r31,...

CRC32演算法實現

crc32 檢錯能力極強,開銷小,易於用編碼器及檢測電路實現。從其檢錯能力來看,它所不能發現的錯誤的機率僅為0.0047 以下。從效能上和開銷上考慮,均遠遠優於奇偶校驗及算術和校驗等方式。因而,在資料儲存和資料通訊領域,crc無處不在 著名的通訊協議x.25的fcs 幀檢錯序列 採用的是crc cc...

深入了解crc32演算法

由於專案需要,解決乙個流 檔案的crc32校驗碼。網上查了很多的資料,發現了此校驗碼和生成多項式以及演算法本身都有關係。對於不同型別的檔案所使用的多項式以及演算法不同,對於不同的生成多項式所生成的crc32表不同,不同的演算法也會產生不同的結果。下面分模擬較兩種不同用途的crc32校驗碼的計算方法。...