CRC32チェックサムはどのように計算されますか?


102

多分私はそれを見ていないだけかもしれませんが、CRC32は不必要に複雑であるか、ウェブ上で見つけることができるどこでも十分に説明されていないようです。

(生成)多項式で除算された、メッセージ値の非キャリーベースの算術除算の余りであることを理解していますが、それを実際に実装すると私はエスケープされます。

私はCRCエラー検出アルゴリズムの痛みのないガイドを読みました。それは理論をかなりうまく行きます、しかし著者は単純な「これだけです」に決して行きません。彼は標準のCRC32アルゴリズムのパラメーターは何かと言っていますが、どのようにしてそれを実現するかを明確に説明することを怠っています。

私を引き付ける部分は、彼が「これだ」と言ってから付け加えたときです。追加したすべての変更を指定してCRC32チェックサムを計算する方法。

  • CRC32の計算方法の簡単な説明はありますか?

テーブルがどのように形成されるかをCでコーディングしようとしました:

for (i = 0; i < 256; i++)
{
    temp = i;

    for (j = 0; j < 8; j++)
    {
        if (temp & 1)
        {
            temp >>= 1;
            temp ^= 0xEDB88320;
        }
        else {temp >>= 1;}
    }
    testcrc[i] = temp;
}

しかし、これはインターネット上の他の場所で見つけた値と一致しない値を生成するようです。私は可能性があり、私はオンラインで見つけるの値を使用しますが、私は彼らが作成されたかを理解したいと思います。

これらの非常に紛らわしい数値を解決するための助けがあれば非常にありがたいです。


9
CRC32テーブルを生成するためのコードは正しいようです。あなたの最下位ビット-最初(逆転)CRC32多項式のは0xEDB88320またMSBitから、最初に(書き込むことができ、通常のように)0x04C11DB7。他の場所で見つけたテーブル値は、同じCRC多項式を使用して生成されましたか?
jschmier、2011年

1
@jschmierこんにちは、私はイムが質問をしているこの男の後ろのステップのように感じますか?stackoverflow.com/questions/62168128/...
bluejayke

:誰が、元のURLがまずいが、Googleが簡単にこの1を含むいくつかのコピー、発見されたことを、上記にリンクされている「A無痛ガイドにCRCエラー検出アルゴリズム」を読んで好奇心旺盛であればzlib.net/crc_v3.txt
ステファン・

回答:


114

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

または、16進数と2進数で:

0x 01 04 C1 1D B7
1 0000 0100 1100 0001 0001 1101 1011 0111

最高項(x 32)は通常明示的に記述されないため、次のように16進数で表すことができます。

0x 04 C1 1D B7

1と0を自由にカウントしてください。ただし1、ビット0(または最初のビット)とxビット1(または2番目のビット)が多項式と一致していることがわかります。

なぜこの多項式なのか?与えられた多項式には標準が必要であり、その標準はIEEE 802.3によって設定されたためです。また、さまざまなビットエラーを効果的に検出する多項式を見つけることは非常に困難です。

CRC-32は、「キャリーのないバイナリ演算」、または基本的に「XORおよびシフト演算」のシリーズと考えることができます。これは技術的に多項式演算と呼ばれています。

それをよりよく理解するために、この掛け算を考えてください:

(x^3 + x^2 + x^0)(x^3 + x^1 + x^0)
= (x^6 + x^4 + x^3
 + x^5 + x^3 + x^2
 + x^3 + x^1 + x^0)
= x^6 + x^5 + x^4 + 3*x^3 + x^2 + x^1 + x^0

xが2を基数とすると、次のようになります。

x^7 + x^3 + x^2 + x^1 + x^0

どうして?3x ^ 3は11x ^ 11です(ただし、必要なのは1桁または0桁のみです)。

=1x^110 + 1x^101 + 1x^100          + 11x^11 + 1x^10 + 1x^1 + x^0
=1x^110 + 1x^101 + 1x^100 + 1x^100 + 1x^11 + 1x^10 + 1x^1 + x^0
=1x^110 + 1x^101 + 1x^101          + 1x^11 + 1x^10 + 1x^1 + x^0
=1x^110 + 1x^110                   + 1x^11 + 1x^10 + 1x^1 + x^0
=1x^111                            + 1x^11 + 1x^10 + 1x^1 + x^0

しかし、数学者はルールをmod 2に変更しました。基本的に、バイナリ多項式mod 2はキャリーやXORなしの単なる加算です。したがって、元の方程式は次のようになります。

=( 1x^110 + 1x^101 + 1x^100 + 11x^11 + 1x^10 + 1x^1 + x^0 ) MOD 2
=( 1x^110 + 1x^101 + 1x^100 +  1x^11 + 1x^10 + 1x^1 + x^0 )
= x^6 + x^5 + x^4 + 3*x^3 + x^2 + x^1 + x^0 (or that original number we had)

私はこれが信念の飛躍であることを知っていますが、これはラインプログラマとしての私の能力を超えています。あなたが筋金入りのCS学生またはエンジニアであるならば、私はこれを破壊することに挑戦します。誰もがこの分析から利益を得るでしょう。

完全な例を作成するには:

   Original message                : 1101011011
   Polynomial of (W)idth 4         :      10011
   Message after appending W zeros : 11010110110000

次に、CRC演算を使用して、拡張されたメッセージをPolyで除算します。これは以前と同じ部門です:

            1100001010 = Quotient (nobody cares about the quotient)
       _______________
10011 ) 11010110110000 = Augmented message (1101011011 + 0000)
=Poly   10011,,.,,....
        -----,,.,,....
         10011,.,,....
         10011,.,,....
         -----,.,,....
          00001.,,....
          00000.,,....
          -----.,,....
           00010,,....
           00000,,....
           -----,,....
            00101,....
            00000,....
            -----,....
             01011....
             00000....
             -----....
              10110...
              10011...
              -----...
               01010..
               00000..
               -----..
                10100.
                10011.
                -----.
                 01110
                 00000
                 -----
                  1110 = Remainder = THE CHECKSUM!!!!

除算により、破棄される商と計算されたチェックサムである剰余が生成されます。これで計算が終了します。通常、チェックサムはメッセージに追加され、結果が送信されます。この場合、送信は11010110111110になります。

32ビットの数値のみを除数として使用し、ストリーム全体を配当として使用します。商を捨てて余りを残してください。メッセージの最後の残りをタックすると、CRC32が作成されます。

平均的な男のレビュー:

         QUOTIENT
        ----------
DIVISOR ) DIVIDEND
                 = REMAINDER
  1. 最初の32ビットを取ります。
  2. シフトビット
  3. 32ビットがDIVISORより小さい場合は、手順2に進みます。
  4. DIVISORによるXOR 32ビット。手順2に進みます。

(ストリームは32ビットで分割可能でなければならないか、パディングする必要があることに注意してください。たとえば、8ビットのANSIストリームはパディングする必要があります。また、ストリームの最後で、分割は停止されます。)


13
末尾の「Average Guy Review」の+1-おそらくこれを一番上に移動することを検討してください-一種のTL。DR:P
aaronsnoswell 2013年

4
@abstractnature 2進数ではなく多項式を除算していることを思い出してください。$ x ^ {n + 1} $から$ x ^ n $を「借りる」ことができないため、「通常の」減算はできません。それらは異なる種類のものです。また、ビットは0または1だけなので、-1はどうなるでしょうか。実際には、フィールド$ Z / 2Z $に係数をもつ多項式のリングで作業しています。これには、0と1の2つの要素しかなく、$ 1 + 1 = 0 $です。cofficientsをフィールドに置くことにより、多項式はいわゆるユークリッドドメインを形成します。これにより、基本的に、最初に行うことを明確に定義することができます。
calavicci 2015年

6
実際の多項式を明確にするために、100000100110000010001110110110111 = 0x104C11DB7です。MSBは暗黙的ですが、実装では考慮に入れる必要があります。多項式は33ビット長である必要があるため(常に残りは32ビット長になる可能性があるため)、常に設定されるため、一部の人々はMSBを省略します。
フェリペT.

2
x^6 + x^5 + x^4 + 3*x^3 + x^2 + x^1 + x^0 ... If we assume x is base 2 then we get: x^7 + x^3 + x^2 + x^1 + x^0。これは数学が機能する方法ではありません。多項式の係数はmod(2)またはGF(2)であり、xはそのままにされるため、x ^ 6 + x ^ 5 + x ^ 4 + x ^ 3 + x ^ 2 + x ^ 1 + x ^になります。 0(3 mod(2)= 1以降)。Tack the remainder on the end of your message-技術的には、メッセージに追加された0ビットから剰余が減算されますが、これはmod(2)の数学であるため、加算と減算はどちらもXORと同じであり、残りとXORされたゼロビットは同じです残りとして。
rcgldr

2
@MarcusJ-- Why did you append four 0s though?明確ではありませんが、crcを計算するソフトウェアアルゴリズムは効果的に0を追加します。ロングハンド除算を使用してCRC計算を示す場合、除算の例が正しく表示されるように0を追加する必要があります。
rcgldr

11

IEEE802.3の場合、CRC-32。メッセージ全体をシリアルビットストリームと考え、メッセージの最後に32個のゼロを追加します。次に、メッセージのすべてのバイトのビットを反転し、最初の32ビットを1の補数にする必要があります。次に、CRC-32多項式0x104C11DB7で除算します。最後に、この除算の32ビットの残りを1で補う必要があります。残りの4バイトのそれぞれをビット反転します。これは、メッセージの最後に追加される32ビットCRCになります。

この奇妙な手順の理由は、最初のイーサネット実装がメッセージを一度に1バイトずつシリアル化し、すべてのバイトの最下位ビットを最初に送信するためです。次に、シリアルビットストリームはシリアルCRC-32シフトレジスタの計算を通過しました。これは単純に補完され、メッセージが完了した後に回線上に送信されました。メッセージの最初の32ビットを補完する理由は、メッセージがすべてゼロであったとしても、すべてゼロのCRCを取得しないようにするためです。


2
これはこれまでのところ最良の回答ですが、「4バイトのビットリバース」を「4バイトのビットリバースに置き換え、それらを1つのエンティティとして扱う」、たとえば「abcdefgh ijklmnop qrstuvwx yzABCDEF」から「FEDCBAzy xwvutsrq」 ponmlkji hgfedcba '。参照:CRC-32ハッシュチュートリアル-AutoHotkeyコミュニティ
vafylec 2017

1
こんにちは、正確な「メッセージ」は何ですか。stackoverflow.com/questions/62168128/...
bluejayke

10

CRCは非常に単純です。ビットとデータとして表された多項式を取り、多項式をデータに分割します(または、データを多項式として表して同じことを行います)。0と多項式の間の残りはCRCです。コードが不完全であることもあり、コードが少し理解しづらいです。tempとtestcrcが宣言されていないため、インデックスに登録されているものや、アルゴリズムを介して実行されているデータの量が不明です。

CRCを理解する方法は、短い多項式(おそらく4ビット)の短いデータ(16ビット程度)を使用していくつかを計算することです。この方法で練習すれば、コーディングの仕方を本当に理解できます。

頻繁に実行している場合、ソフトウェアでのCRCの計算は非常に遅くなります。ハードウェアの計算ははるかに効率的であり、数ゲートで十分です。


1
CRC32またはCRC32bについては、我々は二つの異なる文字列の意味ハッシュ衝突を得るか、私たちは同じCRCを得るのですか
indianwebdevil

1
こんにちは、Imは「多項式をデータに分割する」とは少し混乱していますか?stackoverflow.com/questions/62168128/…多項式のXは何を表していますか?チャンクからのバイトを使用しますか?
bluejayke

7

ウィキペディアの巡回冗長検査CRCの計算の記事に加えて、Reversing CRC-Theory and Practice *というタイトルの論文が参考になると思いました。

CRCを計算するには、基本的に3つのアプローチがあります。代数的アプローチ、ビット指向アプローチ、およびテーブル駆動アプローチです。でCRCを逆-理論と実践 *、これら3つのアルゴリズムの各々 /アプローチは、Cプログラミング言語のCRC32の実装によってAPPENDIXに伴う理論的に説明されています。

* PDFリンク
逆転CRC –理論と実践。
HUベルリンパブリックレポート
SAR-PR-2006-05
2006年5月
著者:
Martin Stigge、HenrykPlötz、WolfMüller、Jens-Peter Redlich


こんにちは、少し詳しく説明していただけますか?
bluejayke

6

私はこの質問への答えを明らかにするためにしばらく費やし、ついに本日CRC-32に関するチュートリアルを公開しました: CRC-32ハッシュチュートリアル-AutoHotkeyコミュニティ

この例では、ASCII文字列「abc」のCRC-32ハッシュを計算する方法を示しています。

calculate the CRC-32 hash for the ASCII string 'abc':

inputs:
dividend: binary for 'abc': 0b011000010110001001100011 = 0x616263
polynomial: 0b100000100110000010001110110110111 = 0x104C11DB7

011000010110001001100011
reverse bits in each byte:
100001100100011011000110
append 32 0 bits:
10000110010001101100011000000000000000000000000000000000
XOR the first 4 bytes with 0xFFFFFFFF:
01111001101110010011100111111111000000000000000000000000

'CRC division':
01111001101110010011100111111111000000000000000000000000
 100000100110000010001110110110111
 ---------------------------------
  111000100010010111111010010010110
  100000100110000010001110110110111
  ---------------------------------
   110000001000101011101001001000010
   100000100110000010001110110110111
   ---------------------------------
    100001011101010011001111111101010
    100000100110000010001110110110111
    ---------------------------------
         111101101000100000100101110100000
         100000100110000010001110110110111
         ---------------------------------
          111010011101000101010110000101110
          100000100110000010001110110110111
          ---------------------------------
           110101110110001110110001100110010
           100000100110000010001110110110111
           ---------------------------------
            101010100000011001111110100001010
            100000100110000010001110110110111
            ---------------------------------
              101000011001101111000001011110100
              100000100110000010001110110110111
              ---------------------------------
                100011111110110100111110100001100
                100000100110000010001110110110111
                ---------------------------------
                    110110001101101100000101110110000
                    100000100110000010001110110110111
                    ---------------------------------
                     101101010111011100010110000001110
                     100000100110000010001110110110111
                     ---------------------------------
                       110111000101111001100011011100100
                       100000100110000010001110110110111
                       ---------------------------------
                        10111100011111011101101101010011

remainder: 0b10111100011111011101101101010011 = 0xBC7DDB53
XOR the remainder with 0xFFFFFFFF:
0b01000011100000100010010010101100 = 0x438224AC
reverse bits:
0b00110101001001000100000111000010 = 0x352441C2

thus the CRC-32 hash for the ASCII string 'abc' is 0x352441C2

1
より高速が必要な場合は、Intelの一部のエンジニアが2006年頃にマシンのデータバス幅の通常4バイトまたは8バイトを同時に使用する方法を考えました。学術論文:static.aminer.org/pdf/PDF/000/432/446/…Sourceforge上の プロジェクト:sourceforge.net/projects/slicing-by-8 General crcページ:create.stephan-brumme.com/crc32
Alanコリー

1
こんにちはありがとうございます。見栄えは良いですが、多項式の値はどのように正確に取得しますか?Xは正確には何を表していますか?そして、それがx ^ 32と言うとき、そのxは32の累乗^ですか、それともビットごとの演算子ですか?stackoverflow.com/questions/62168128/...
bluejayke


1

crc32を思い出させるために減らすには、次のことを行う必要があります。

  1. 各バイトのビットを反転
  2. xor 0xFFの最初の4バイト(これは先行する0のエラーを回避するためです)
  3. 最後にパディングを追加します(これは、最後の4バイトをハッシュに含めるためです)。
  4. リマインダーを計算する
  5. もう一度ビットを逆にします
  6. 結果を再度xorします。

コードではこれは次のとおりです。


func CRC32 (file []byte) uint32 {
    for i , v := range(file) {
        file[i] = bits.Reverse8(v)
    }
    for i := 0; i < 4; i++ {
        file[i] ^= 0xFF
    }

    // Add padding
    file = append(file, []byte{0, 0, 0, 0}...)
    newReminder := bits.Reverse32(reminderIEEE(file))

    return newReminder ^ 0xFFFFFFFF
}

ここで、reminderIEEEはGF(2)[x]の純粋なリマインダーです


1
これを理解するのに少し問題がありますか?stackoverflow.com/questions/62168128/...
bluejayke

1
こんにちは、@ bluejayke、このライブラリgithub.com/furstenheim/sparse_crc32/blob/master/main.goを確認してくださいスパースファイル用のcrc32を実装しています。これは最適化されていないため、通常の実装よりも追跡が容易です。GF(2)[x]の部分が理解できない可能性があります。基本的に、x ^ 3 + xは1010を意味し、x ^ 4 + x + 1は10011を意味します。次に、除算を実行する必要があります。たとえば、x ^ 3 + xはx *(x ^ 2 + 1)です。したがって、xを超えるx ^ 3 + xのリマインダーは0ですが、x ^ 2を超えるとx ^ 2 * x + xになります。つまり、リマインダーはxになります。
Gabriel Furstenheim

1
@bluejayke and reminderIEEEは、よく知られた多項式であるIEEE多項式に対するリマインダーを意味します
Gabriel Furstenheim

こんにちは。返信ありがとうございます。(JavaScriptの目的で)多項式で "x"が何を表すかを理解しようとしています。「x」は私がここで見逃しているもののある種のコードワードですか?ここで私を混乱させる用語がたくさんあります。以前にCRC32について聞いたことがなく、検索した後でも実際に説明されていることがわかりませんでした。たとえば、PNGの場合、「チャンクごとのCRC」をとる必要があるとありますが、それは「チャンク内のすべてのデータについて」という意味ですか?しかし、どうすれば多項式に「プラグイン」できますか?「x」は何を表していますか?また、x ^ 32と表示されている場合は、Math.pow(x、32)またはビット単位の^のようなものです
bluejayke

1
こんにちは@ bluejayke、xは計算を簡単にするための抽象概念です。何かで代用されることは期待されていません。x ^ 2形式的な乗算としてのx * xを意味します。ここchrisballance.com/wp-content/uploads/2015/10/CRC-Primer.htmlには、その分割についてのわかりやすい説明があります。私が私の答えで試したのは、除算(そのリンク内)と実際の計算の間のギャップを埋めることでした
Gabriel Furstenheim
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.