Wie wird eine CRC32-Prüfsumme berechnet?

102

Vielleicht sehe ich es einfach nicht, aber CRC32 scheint entweder unnötig kompliziert oder unzureichend erklärt zu sein, wo immer ich es im Web finden kann.

Ich verstehe, dass es der Rest einer nicht Carry-basierten arithmetischen Division des Nachrichtenwerts ist, geteilt durch das (Generator-) Polynom, aber die tatsächliche Implementierung davon entgeht mir.

Ich habe einen schmerzlosen Leitfaden zu CRC-Fehlererkennungsalgorithmen gelesen , und ich muss sagen, dass er nicht schmerzlos war. Es geht ziemlich gut über die Theorie, aber der Autor kommt nie zu einem einfachen "das ist es". Er sagt zwar, welche Parameter für den Standard-CRC32-Algorithmus gelten, vernachlässigt jedoch, klar darzulegen, wie Sie dazu gelangen.

Der Teil, der mich erwischt, ist, wenn er sagt "das ist es" und dann hinzufügt: "Oh, übrigens, es kann umgekehrt oder mit unterschiedlichen Anfangsbedingungen begonnen werden" und keine klare Antwort auf den endgültigen Weg gibt der Berechnung einer CRC32-Prüfsumme unter Berücksichtigung aller Änderungen, die er gerade hinzugefügt hat.

  • Gibt es eine einfachere Erklärung für die Berechnung von CRC32?

Ich habe versucht, in C zu codieren, wie die Tabelle gebildet wird:

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;
}

Dies scheint jedoch Werte zu erzeugen, die nicht mit den Werten übereinstimmen, die ich an anderer Stelle im Internet gefunden habe. Ich könnte die online gefundenen Werte verwenden, möchte aber verstehen, wie sie erstellt wurden.

Jede Hilfe bei der Aufklärung dieser unglaublich verwirrenden Zahlen wäre sehr dankbar.

Aquanar
quelle
9
Ihr Code zum Generieren der CRC32-Tabelle scheint korrekt zu sein. Ihr lsbit-first ( umgekehrt ) CRC32-Polynom von 0xEDB88320kann auch msbit-first ( normal ) als geschrieben werden 0x04C11DB7. Wurden die Tabellenwerte, die Sie an anderer Stelle gefunden haben, mit demselben CRC-Polynom generiert?
Jschmier
1
@jschmier hi, ich fühle mich wie ich einen Schritt hinter diesem Kerl bin, der die Fragen stellt? stackoverflow.com/questions/62168128/…
bluejayke
Wenn jemand anderes neugierig ist, "Eine schmerzlose Anleitung zu CRC-Fehlererkennungsalgorithmen" zu lesen, die oben verlinkt ist, wird diese ursprüngliche URL abgespritzt, aber Google hat leicht mehrere Kopien gefunden, einschließlich dieser: zlib.net/crc_v3.txt
Stéphane

Antworten:

114

Das Polynom für CRC32 lautet:

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

Oder in hex und binär:

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

Der höchste Term (x 32 ) wird normalerweise nicht explizit geschrieben, daher kann er genauso wie in hexadezimaler Darstellung dargestellt werden

0x 04 C1 1D B7

Fühlen Sie sich frei, die Einsen und Nullen zu zählen, aber Sie werden feststellen, dass sie mit dem Polynom übereinstimmen, wobei 1Bit 0 (oder das erste Bit) und xBit 1 (oder das zweite Bit) ist.

Warum dieses Polynom? Weil es einen Standard für ein Polynom geben muss und der Standard von IEEE 802.3 festgelegt wurde. Es ist auch äußerst schwierig, ein Polynom zu finden, das verschiedene Bitfehler effektiv erkennt.

Sie können sich den CRC-32 als eine Reihe von "Binärarithmetik ohne Träger" oder im Grunde als "XOR- und Schichtoperationen" vorstellen. Dies wird technisch als Polynomarithmetik bezeichnet.

Um es besser zu verstehen, denken Sie an diese Multiplikation:

(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

Wenn wir annehmen, dass x Basis 2 ist, erhalten wir:

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

Warum? Da 3x ^ 3 11x ^ 11 ist (aber wir brauchen nur 1 oder 0 Vorziffer), übertragen wir:

=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

Aber Mathematiker haben die Regeln so geändert, dass es Mod 2 ist. Im Grunde genommen ist jedes binäre Polynom Mod 2 nur eine Addition ohne Carry oder XORs. Unsere ursprüngliche Gleichung sieht also so aus:

=( 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)

Ich weiß, dass dies ein Glaubenssprung ist, aber dies übersteigt meine Fähigkeiten als Linienprogrammierer. Wenn Sie ein Hardcore-CS-Student oder Ingenieur sind, fordere ich Sie auf, dies aufzuschlüsseln. Jeder wird von dieser Analyse profitieren.

Um ein vollständiges Beispiel zu erarbeiten:

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

Jetzt teilen wir die erweiterte Nachricht durch die Poly mithilfe der CRC-Arithmetik. Dies ist die gleiche Unterteilung wie zuvor:

            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!!!!

Die Division ergibt einen Quotienten, den wir wegwerfen, und einen Rest, der die berechnete Prüfsumme ist. Damit ist die Berechnung beendet. Normalerweise wird die Prüfsumme dann an die Nachricht angehängt und das Ergebnis übertragen. In diesem Fall wäre die Übertragung: 11010110111110.

Verwenden Sie nur eine 32-Bit-Zahl als Divisor und Ihren gesamten Stream als Dividende. Wirf den Quotienten raus und behalte den Rest. Heften Sie den Rest am Ende Ihrer Nachricht an und Sie haben einen CRC32.

Durchschnittliche Bewertung:

         QUOTIENT
        ----------
DIVISOR ) DIVIDEND
                 = REMAINDER
  1. Nimm die ersten 32 Bits.
  2. Bits verschieben
  3. Wenn 32 Bit kleiner als DIVISOR sind, fahren Sie mit Schritt 2 fort.
  4. XOR 32 Bit von DIVISOR. Weiter zu Schritt 2.

(Beachten Sie, dass der Stream durch 32 Bit teilbar sein muss oder aufgefüllt werden muss. Beispielsweise müsste ein 8-Bit-ANSI-Stream aufgefüllt werden. Auch am Ende des Streams wird die Teilung angehalten.)

ilkkachu
quelle
13
+1 für die "Average Guy Review" am Ende - vielleicht sollten Sie dies ganz nach oben verschieben - eine Art TL; DR: P
aaronsnoswell
4
@abstractnature Denken Sie daran, dass wir Polynome teilen, nicht nur Binärzahlen. Wir können keine "normale" Subtraktion durchführen, weil wir $ x ^ n $ nicht von $ x ^ {n + 1} $ "ausleihen" können; Sie sind verschiedene Arten von Dingen. Da die Bits nur 0 oder 1 sind, was wäre -1 überhaupt? Wirklich, wir arbeiten im Ring von Polynomen mit Koeffizienten im Feld $ Z / 2Z $, das nur zwei Elemente hat, 0 und 1, und wobei $ 1 + 1 = 0 $. Indem die Cofficients in ein Feld eingefügt werden, bilden die Polynome eine sogenannte euklidische Domäne, die es im Grunde nur ermöglicht, das, was wir versuchen, zunächst genau zu definieren.
Calavicci
6
Nur um das tatsächliche Polynom zu verdeutlichen, lautet 100000100110000010001110110110111 = 0x104C11DB7. Das MSB ist implizit, sollte jedoch bei einer Implementierung berücksichtigt werden. Da es immer gesetzt wird, weil das Polynom 33 Bit lang sein muss (der Rest kann also 32 Bit lang sein), lassen einige Leute das MSB weg.
Felipe 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. So funktioniert die Mathematik nicht. Die Koeffizienten zum Polynom sind mod (2) oder GF (2), die x werden in Ruhe gelassen, was zu x ^ 6 + x ^ 5 + x ^ 4 + x ^ 3 + x ^ 2 + x ^ 1 + x ^ führt 0 (da 3 mod (2) = 1). Tack the remainder on the end of your message- Technisch gesehen wird der Rest von den 0 Bits subtrahiert, die an die Nachricht angehängt wurden. Da dies jedoch mod (2) math ist, sind sowohl addieren als auch subtrahieren dieselben wie XOR, und die mit dem Rest XOR'ed Null-Bits sind dieselben als der Rest.
rcgldr
2
@MarcusJ - Why did you append four 0s though?- Die Softwarealgorithmen zur Berechnung von crc hängen die Nullen effektiv an, obwohl dies nicht ersichtlich ist. Wenn die CRC-Berechnung mithilfe der Langhanddivision angezeigt wird, müssen Nullen angehängt werden, damit das Divisionsbeispiel korrekt angezeigt wird.
rcgldr
11

Für IEEE802.3 CRC-32. Stellen Sie sich die gesamte Nachricht als seriellen Bitstrom vor und hängen Sie 32 Nullen an das Ende der Nachricht an. Als nächstes MÜSSEN Sie die Bits JEDES Bytes der Nachricht umkehren und die ersten 32 Bits durch eine 1 ergänzen. Teilen Sie nun durch das CRC-32-Polynom 0x104C11DB7. Schließlich müssen Sie den 32-Bit-Rest dieser Division durch 1 ergänzen und jedes der 4 Bytes des Restes bitumkehren. Dies wird die 32-Bit-CRC, die an das Ende der Nachricht angehängt wird.

Der Grund für diese seltsame Prozedur ist, dass die ersten Ethernet-Implementierungen die Nachricht byteweise serialisieren und das niedrigstwertige Bit jedes Bytes zuerst übertragen. Der serielle Bitstrom durchlief dann eine serielle CRC-32-Schieberegisterberechnung, die einfach ergänzt und nach Abschluss der Nachricht auf der Leitung gesendet wurde. Der Grund für das Ergänzen der ersten 32 Bits der Nachricht ist, dass Sie keine CRC mit allen Nullen erhalten, selbst wenn die Nachricht nur Nullen war.

Pavlo Bobrek
quelle
2
Dies ist die bisher beste Antwort hier, obwohl ich "Bit-Reverse jedes der 4 Bytes" durch "Bit-Reverse der 4 Bytes" ersetzen würde, indem ich sie als eine Entität behandle, z. B. "abcdefgh ijklmnop qrstuvwx yzABCDEF" durch "FEDCBAzy xwvutsrq" ponmlkji hgfedcba '. Siehe auch: CRC-32-Hash-Tutorial - AutoHotkey-Community .
Vafylec
1
Hallo, welche "Nachricht" genau; y kehren Sie um? stackoverflow.com/questions/62168128/…
bluejayke
10

Ein CRC ist ziemlich einfach; Sie nehmen ein Polynom, das als Bits und Daten dargestellt wird, und teilen das Polynom in die Daten (oder Sie stellen die Daten als Polynom dar und tun dasselbe). Der Rest, der zwischen 0 und dem Polynom liegt, ist der CRC. Ihr Code ist etwas schwer zu verstehen, auch weil er unvollständig ist: temp und testcrc werden nicht deklariert, daher ist unklar, was indiziert wird und wie viele Daten durch den Algorithmus laufen.

Der Weg, CRCs zu verstehen, besteht darin, zu versuchen, einige mit einem kurzen Datenelement (ca. 16 Bit) mit einem kurzen Polynom zu berechnen - vielleicht 4 Bit. Wenn Sie auf diese Weise üben, werden Sie wirklich verstehen, wie Sie es codieren können.

Wenn Sie dies häufig tun, ist die Berechnung eines CRC in Software recht langsam. Hardware-Berechnungen sind viel effizienter und erfordern nur wenige Gates.

Wirbelwind
quelle
1
Erhalten wir für CRC32 oder CRC32b eine Hash-Kollisionsbedeutung für zwei verschiedene Zeichenfolgen
? Erhalten
1
Hallo, ich bin ein bisschen verwirrt, was du mit "die Polynome in die Daten teilen" meinst. stackoverflow.com/questions/62168128/… Was ist X im Polynom, das durch dargestellt wird? Benutze ich die anderen Bytes aus dem Block?
Bluejayke
7

Zusätzlich zur zyklischen Redundanzprüfung und Berechnung von CRC- Artikeln in Wikipedia fand ich ein Papier mit dem Titel Reversing CRC - Theory and Practice * als gute Referenz.

Es gibt im Wesentlichen drei Ansätze zur Berechnung eines CRC: einen algebraischen Ansatz, einen bitorientierten Ansatz und einen tabellengesteuerten Ansatz. In Umkehrung von CRC - Theorie und Praxis * wird jeder dieser drei Algorithmen / Ansätze theoretisch im ANHANG mit einer Implementierung für CRC32 in der Programmiersprache C erläutert.

* PDF Link
Umkehrung von CRC - Theorie und Praxis.
HU Berlin Öffentlicher Bericht
SAR-PR-2006-05
Mai 2006
Autoren:
Martin Stigge, Henryk Plötz, Wolf Müller, Jens-Peter Redlich

jschmier
quelle
Hallo, kannst du etwas näher darauf eingehen?
Bluejayke
6

Ich habe eine Weile versucht, die Antwort auf diese Frage zu finden, und heute endlich ein Tutorial zu CRC-32 veröffentlicht: CRC-32-Hash-Tutorial - AutoHotkey Community

In diesem Beispiel zeige ich, wie der CRC-32-Hash für die ASCII-Zeichenfolge 'abc' berechnet wird:

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
vafylec
quelle
1
Wenn Sie mehr Geschwindigkeit wünschen, haben einige Ingenieure von Intel um 2006 eine Methode entwickelt, bei der normalerweise 4 oder 8 Byte der Datenbusbreite der Maschine gleichzeitig verwendet werden. Wissenschaftliches Papier: static.aminer.org/pdf/PDF/000/432/446/… Projekt zu Sourceforge: sourceforge.net/projects/slicing-by-8 Allgemeine CRC-Seite: create.stephan-brumme.com/crc32
Alan Corey
1
Hallo danke sieht gut aus, aber wie genau bekommst du den Polynomwert? Was bedeutet X genau? Und wenn x ^ 32 steht, ist das x hoch 32 oder der bitweise Operator ^? stackoverflow.com/questions/62168128/…
bluejayke
1

Um crc32 auf die Erinnerung zu reduzieren, müssen Sie:

  1. Bits auf jedem Byte invertieren
  2. xoder die ersten vier Bytes mit 0xFF (um Fehler bei den führenden Nullen zu vermeiden)
  3. Fügen Sie am Ende eine Auffüllung hinzu (damit die letzten 4 Bytes am Hash teilnehmen)
  4. Berechnen Sie die Erinnerung
  5. Kehren Sie die Bits erneut um
  6. xoder das Ergebnis erneut.

Im Code ist dies:


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
}

wobei memorIEEE die reine Erinnerung an GF (2) ist [x]

Gabriel Furstenheim
quelle
1
Ich habe ein bisschen (Wortspiel beabsichtigt) Probleme, das zu verstehen? stackoverflow.com/questions/62168128/…
bluejayke
1
hey @bluejayke, überprüfen Sie diese Bibliothek github.com/furstenheim/sparse_crc32/blob/master/main.go implementiert es das crc32 für spärliche Dateien, Sie können dort die wesentlichen Details der Berechnung sehen. Es ist nicht optimiert, daher ist es einfacher zu verfolgen als normale Implementierungen. Es kann sein, dass Sie den GF (2) [x] -Teil nicht verstehen. Grundsätzlich bedeutet x ^ 3 + x 1010, x ^ 4 + x + 1 bedeutet 10011. Dann müssen Sie eine Division durchführen, zum Beispiel x ^ 3 + x ist x * (x ^ 2 + 1). Die Erinnerung an x ​​^ 3 + x über x ist also 0, aber über x ^ 2 wäre es x ^ 2 * x + x, dh die Erinnerung wäre x.
Gabriel Furstenheim
1
@bluejayke und MahnungIEEE bedeutet Erinnerung an ein bekanntes Polynom, das IEEE-Polynom
Gabriel Furstenheim
Hallo nochmal, danke für deine Antwort. Ich versuche nur zu verstehen (für Javascript-Zwecke), was das "x" im Polynom darstellt. Ist "x" eine Art Codewort für etwas, das mir hier fehlt? Es gibt eine Menge Begriffe, die mich hier verwirren, ich habe noch nie von CRC32 gehört, und selbst nach der Suche konnte ich es nicht finden, was tatsächlich erklärt wurde. Für ein PNG heißt es beispielsweise, dass ich den "CRC für jeden Block" nehmen muss. Bedeutet das "für alle Daten im Block"? Aber wie "stecke" ich es in das Polynom? Was bedeutet "x"? Auch wenn es x ^ 32 sagt, ist das wie Math.pow (x, 32) oder das bitweise ^
bluejayke
1
Hallo @bluejayke, x ist eine Abstraktion, um Berechnungen zu vereinfachen. Es wird nicht erwartet, dass es durch irgendetwas ersetzt wird. x ^ 2 Ich meine x * x als formale Multiplikation. Hier finden Sie eine nette Erklärung dieser Aufteilung. Chrisballance.com/wp-content/uploads/2015/10/CRC-Primer.html . Was ich mit meiner Antwort versuchte, war, die Lücke zwischen der Division (in diesem Link) und der eigentlichen Berechnung zu füllen
Gabriel Furstenheim