CRC32 sağlama toplamı nasıl hesaplanır?


104

Belki de görmüyorum, ama CRC32 ya gereksiz yere karmaşık görünüyor ya da internette bulabildiğim herhangi bir yerde yeterince açıklanmıyor.

Mesaj değerinin taşınmaya dayalı olmayan aritmetik bölümünden kalan kısmının (üretici) polinomuna bölündüğünü anlıyorum, ancak gerçek uygulaması benden kaçıyor.

CRC Hata Algılama Algoritmaları İçin Ağrısız Bir Kılavuz okudum ve ağrısız olmadığını söylemeliyim. Teorinin üzerinden oldukça iyi geçiyor, ancak yazar hiçbir zaman basit bir "işte bu" diyemiyor. Standart CRC32 algoritması için parametrelerin ne olduğunu söylüyor, ancak ona nasıl ulaşacağınızı açıkça belirtmeyi ihmal ediyor.

Beni anlayan kısım, "işte bu" dediği ve sonra eklediği, "bu arada, tersine çevrilebilir veya farklı başlangıç ​​koşullarıyla başlatılabilir" ve son yolun ne olduğuna dair net bir cevap vermemesidir eklediği tüm değişiklikler göz önüne alındığında bir CRC32 sağlama toplamının hesaplanması.

  • CRC32'nin nasıl hesaplandığına dair daha basit bir açıklama var mı?

Tablonun nasıl oluşturulduğunu C'de kodlamaya çalıştım:

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

ancak bu, İnternette başka yerlerde bulduğum değerlerle tutarsız değerler üretiyor gibi görünüyor. Ben olabilir Çevrimiçi bulundu değerleri kullanmak, ama onlar nasıl yaratıldığını anlamak istiyorum.

Bu inanılmaz derecede kafa karıştırıcı sayıları temizlemede herhangi bir yardım çok takdir edilecektir .


9
CRC32 tablosunu oluşturmak için kodunuz doğru görünüyor. Lsbit-first ( tersine çevrilmiş ) CRC32 polinomunuz 0xEDB88320ayrıca msbit-first ( normal ) olarak yazılabilir 0x04C11DB7. Başka bir yerde bulduğunuz tablo değerleri aynı CRC polinomu kullanılarak mı oluşturuldu?
jschmier

1
@jschmier merhaba, soruları soran bu adamın arkasında bir adım olduğumu hissediyorum. stackoverflow.com/questions/62168128/…
bluejayke

Yukarıda bağlantısı verilen "CRC Hata Algılama Algoritmaları İçin Ağrısız Bir Kılavuz" u merak eden başka biri varsa, bu orijinal URL hapsedilir
Stéphane

Yanıtlar:


120

CRC32 için polinom:

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

Veya onaltılık ve ikili olarak:

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

En yüksek terim (x 32 ) genellikle açık bir şekilde yazılmaz, bu nedenle aynı şekilde onaltılık olarak gösterilebilir.

0x 04 C1 1D B7

1'leri ve 0ları saymaktan çekinmeyin, ancak bunların polinomla eşleştiğini göreceksiniz, burada 1bit 0 (veya ilk bit) ve xbit 1 (veya ikinci bit).

Neden bu polinom? Çünkü polinom için bir standart olması gerekiyor ve standart IEEE 802.3 tarafından belirlendi. Ayrıca, farklı bit hatalarını etkin bir şekilde algılayan bir polinom bulmak son derece zordur.

CRC-32'yi bir dizi "Taşımasız İkili Aritmetik" veya temelde "XOR ve kaydırma işlemleri" olarak düşünebilirsiniz. Bu teknik olarak Polinom Aritmetik olarak adlandırılır.

Daha iyi anlamak için şu çarpımı düşünün:

(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'in 2 tabanı olduğunu varsayarsak, şunu elde ederiz:

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

Neden? 3x ^ 3, 11x ^ 11 olduğundan (ancak yalnızca 1 veya 0 ön basamağa ihtiyacımız var), bu nedenle şunları aktarıyoruz:

=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

Ancak matematikçiler kuralları mod 2 olacak şekilde değiştirdiler. Yani temelde herhangi bir ikili polinom mod 2, taşıma veya XOR içermeyen bir toplamadır. Yani orijinal denklemimiz şöyle görünür:

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

Bunun bir inanç sıçraması olduğunu biliyorum ama bu benim satır programcısı olarak yeteneğimin ötesinde. Sert çekirdekli bir bilgisayar bilimleri öğrencisi veya mühendisi iseniz, bunu yıkmaya meydan okuyorum. Bu analizden herkes yararlanacak.

Öyleyse tam bir örnek oluşturmak için:

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

Şimdi, CRC aritmetiği kullanarak artırılmış Mesajı Poly'ye böleriz. Bu, öncekiyle aynı bölüm:

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

Bölme, attığımız bir bölüm ve hesaplanan sağlama toplamı olan bir kalan verir. Bu hesaplamayı bitirir. Genellikle, sağlama toplamı daha sonra mesaja eklenir ve sonuç iletilir. Bu durumda iletim şöyle olacaktır: 11010110111110.

Bölen olarak yalnızca 32 bitlik bir sayı kullanın ve yayınınızın tamamını temettü olarak kullanın. Bölümü atın ve kalanı saklayın. Mesajınızın sonunda kalan kısmı işaretleyin ve bir CRC32'ye sahip olun.

Ortalama erkek incelemesi:

         QUOTIENT
        ----------
DIVISOR ) DIVIDEND
                 = REMAINDER
  1. İlk 32 biti alın.
  2. Kaydırma bitleri
  3. 32 bit DIVISOR'dan azsa, 2. adıma gidin.
  4. DIVISOR tarafından XOR 32 bit. 2. adıma gidin.

(Akışın 32 bit'e bölünmesi veya doldurulması gerektiğini unutmayın. Örneğin, 8 bitlik bir ANSI akışının doldurulması gerekir. Ayrıca akışın sonunda bölme durdurulur.)


14
Sonunda "Ortalama Erkek İncelemesi" için +1 - belki bunu en üste taşımayı düşünün - bir çeşit TL; DR: P
aaronsnoswell

4
@abstractnature Sadece ikili sayıları değil, polinomları da böldüğümüzü unutmayın. "Normal" çıkarma yapamayız çünkü $ x ^ n $ 'ı $ x ^ {n + 1} $' dan "ödünç alamayız"; onlar farklı türde şeylerdir. Ayrıca, bitler sadece 0 veya 1 olduğundan, -1 bile ne olurdu? Gerçekten, katsayıları $ Z / 2Z $ alanında, 0 ve 1 olmak üzere sadece iki elemanı olan ve $ 1 + 1 = 0 $ olan polinomlar halkasında çalışıyoruz. Kahveleri bir alana yerleştirerek, polinomlar Öklid Alanı adı verilen şeyi oluşturur ve bu da temelde yapmaya çalıştığımız şeyin ilk etapta iyi tanımlanmasına izin verir.
calavicci

6
Sadece gerçek polinomun 100000100110000010001110110110111 = 0x104C11DB7 olduğunu açıklığa kavuşturmak için. MSB örtüktür, ancak yine de bir uygulamada dikkate alınmalıdır. Her zaman ayarlanacağı için polinomun 33 bit uzunluğunda olması gerektiğinden (yani geri kalanı 32 bit uzunluğunda olabilir) bazı insanlar MSB'yi çıkarır.
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. Matematik böyle çalışmıyor. Polinom katsayıları mod (2) veya GF (2) 'dir, x'ler tek başına bırakılır ve sonuçta x ^ 6 + x ^ 5 + x ^ 4 + x ^ 3 + x ^ 2 + x ^ 1 + x ^ 0 (3 mod (2) = 1'den beri). Tack the remainder on the end of your message- teknik olarak kalan, mesaja eklenen 0 bitten çıkarılır, ancak bu mod (2) matematiği olduğundan, hem toplama hem de çıkarma XOR ile aynıdır ve kalanıyla XOR sıfır biti aynıdır geri kalan olarak.
rcgldr

2
@MarcusJ - Why did you append four 0s though?- crc'yi hesaplamak için kullanılan yazılım algoritmaları, görünür olmasa da 0'ları etkili bir şekilde ekler. Uzun el bölme kullanılarak CRC hesaplaması gösteriliyorsa, bölme örneğinin doğru görünmesi için 0'ların eklenmesi gerekir.
rcgldr

11

IEEE802.3, CRC-32 için. Tüm mesajı bir seri bit akışı olarak düşünün, mesajın sonuna 32 sıfır ekleyin. Sonra, mesajın HER baytının bitlerini ters çevirmeli ve ilk 32 biti bir 1'i tamamlamalısınız. Şimdi CRC-32 polinomu, 0x104C11DB7 ile bölün. Son olarak, 1'in bu bölümün 32 bitlik kalanını, kalan 4 baytın her birini bit tersine çevirmesi gerekir. Bu, mesajın sonuna eklenen 32 bitlik CRC olur.

Bu tuhaf prosedürün nedeni, ilk Ethernet uygulamalarının mesajı her seferinde bir bayt seri hale getirmesi ve ilk önce her baytın en az anlamlı bitini iletmesidir. Seri bit akışı daha sonra seri bir CRC-32 kaydırma yazmacı hesaplamasından geçti, bu basitçe tamamlandı ve mesaj tamamlandıktan sonra kabloya gönderildi. Mesajın ilk 32 bitini tamamlamanın nedeni, mesajın tamamı sıfır olsa bile tamamen sıfır bir CRC almamanızdır.


2
Şu ana kadarki en iyi cevap bu olsa da, '4 baytın her birini bit-tersine çevir' yerine '4 baytı bit ters çevirip onları tek bir varlık olarak ele alsam da' abcdefgh ijklmnop qrstuvwx yzABCDEF 'ile' FEDCBAzy xwvutsrq ponmlkji hgfedcba '. Ayrıca bakınız: CRC-32 hash öğreticisi - AutoHotkey Topluluğu .
vafylec

1
merhaba, tam olarak hangi "mesaj"; y ile ters çeviriyorsunuz? stackoverflow.com/questions/62168128/…
bluejayke

10

Bir CRC oldukça basittir; bit ve veri olarak temsil edilen bir polinomu alır ve polinomu verilere bölersiniz (veya veriyi bir polinom olarak temsil edersiniz ve aynı şeyi yaparsınız). 0 ile polinom arasında kalan, CRC'dir. Kodunuzun anlaşılması biraz zor, çünkü kısmen eksik: temp ve testcrc bildirilmedi, bu nedenle neyin indekslendiği ve algoritmada ne kadar verinin çalıştığı belirsiz.

CRC'leri anlamanın yolu, kısa bir veri parçasını (16 bit veya benzeri) kısa bir polinomla (belki 4 bit) kullanarak birkaçını hesaplamaya çalışmaktır. Bu şekilde pratik yaparsanız, onu nasıl kodlayabileceğinizi gerçekten anlayacaksınız.

Sık sık yapıyorsanız, CRC'nin yazılımda hesaplanması oldukça yavaştır. Donanım hesaplaması çok daha verimlidir ve yalnızca birkaç kapı gerektirir.


1
CRC32 veya CRC32b için, iki farklı dizge için hash çarpışması anlamını alıyor muyuz? Aynı CRC'yi mi
alıyoruz

1
merhaba, "polinomları verilere bölmek" ile ne demek istediğini biraz karıştırdım. stackoverflow.com/questions/62168128/… ile temsil edilen polinomdaki X nedir? Oter baytlarını öbekten kullanıyor muyum?
bluejayke

7

Wikipedia Döngüsel artıklık denetimi ve CRC makalelerinin Hesaplanmasına ek olarak, iyi bir referans olarak Reversing CRC - Theory and Practice * başlıklı bir makale buldum .

Bir CRC'yi hesaplamak için esasen üç yaklaşım vardır: cebirsel bir yaklaşım, bit odaklı bir yaklaşım ve tabloya dayalı bir yaklaşım. In CRC Ters - Teorisi ve Uygulaması * , bu üç algoritmaların her / C programlama dilinde CRC32 için bir uygulama tarafından LAHİKA eşlik teoride açıklanmıştır yaklaşımlar.

* PDF Link
Reversing CRC - Teori ve Uygulama.
HU Berlin Kamu Raporu
SAR-PR-2006-05
Mayıs 2006
Yazarlar:
Martin Stigge, Henryk Plötz, Wolf Müller, Jens-Peter Redlich


merhaba, biraz detaylandırır mısınız?
bluejayke

7

Bu sorunun cevabını bulmaya çalışırken bir süre harcadım ve sonunda bugün CRC-32 hakkında bir eğitim yayınladım: CRC-32 hash öğreticisi - AutoHotkey Topluluğu

Bu örnekte, ASCII dizisi 'abc' için CRC-32 karmasının nasıl hesaplanacağını göstereceğim:

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
Daha fazla hız istiyorsanız, Intel'de 2006'da bazı mühendisler tarafından tipik olarak aynı anda 4 veya 8 baytlık makinenin veri yolu genişliğini kullanan bir yöntem vardı. Akademik makale: static.aminer.org/pdf/PDF/000/432/446/… Sourceforge'daki proje: sourceforge.net/projects/slicing-by-8 Genel crc sayfası: create.stephan-brumme.com/crc32
Alan Corey

1
Merhaba teşekkürler harika görünüyor, ama polinom değerini tam olarak nasıl elde edersiniz? X tam olarak neyi temsil ediyor? Ve x ^ 32 dediğinde, bu x üssü 32 mi, yoksa bitsel operatör ^mü? stackoverflow.com/questions/62168128/…
bluejayke


1

Crc32'yi hatırlatıcı almaya indirgemek için yapmanız gerekenler:

  1. Her bayttaki bitleri ters çevirin
  2. x veya 0xFF ile ilk dört bayt (bu, baştaki 0'larda hataları önlemek içindir)
  3. Sona padding ekleyin (bu, son 4 baytın hash'de yer almasını sağlamak içindir)
  4. Hatırlatıcıyı hesaplayın
  5. Bitleri tekrar ters çevirin
  6. xveya sonucu tekrar.

Kodda bu:


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
}

IEEE'nin GF (2) [x] üzerindeki saf hatırlatıcı olduğu hatırlatma


1
Bunu anlamakta biraz (amaçlanan) sorun mu yaşıyorum? stackoverflow.com/questions/62168128/…
bluejayke

1
hey @bluejayke, bu kitaplığı kontrol edin github.com/furstenheim/sparse_crc32/blob/master/main.go, crc32'yi seyrek dosyalar için uygular, orada hesaplamayla ilgili nitty cesur ayrıntıları görebilirsiniz. Optimize edilmediğinden, normal uygulamalara göre takip edilmesi daha kolaydır. Anlamadığınız şey GF (2) [x] kısmı olabilir. X ^ 3 + x, 1010, x ^ 4 + x + 1, 10011 anlamına gelir. O zaman bölme yapmanız gerekir, örneğin x ^ 3 + x, x * (x ^ 2 + 1) 'dir. dolayısıyla x ^ 3 + x bölü x 0 olur, ancak x ^ 2 üzerinde bu x ^ 2 * x + x olur, yani hatırlatıcı x olur.
Gabriel Furstenheim

1
@bluejayke ve reminderIEEE, iyi bilinen bir polinom olan IEEE polinomuna karşı hatırlatma anlamına gelir
Gabriel Furstenheim

tekrar merhaba, cevabınız için teşekkürler Sadece "x" in polinomda neyi temsil ettiğini anlamaya çalışıyorum (javascript amaçları için). "X" burada kaçırdığım bir şeyin bir tür kod-kelimesi mi? Burada kafamı karıştıran bir sürü terim var, CRC32'yi daha önce hiç duymadım ve aradıktan sonra bile aslında açıklanmasını bulamadım. Örneğin bir PNG için "Her parça için CRC" almam gerektiğini söylüyor, bu "parçadaki tüm veriler için" anlamına mı geliyor? Ama polinomu nasıl "bağlayabilirim"? "X" neyi temsil eder? Ayrıca x ^ 32 dediğinde, Math.pow (x, 32) veya bitwise ^
bluejayke

1
Merhaba @bluejayke, x, hesaplamaları kolaylaştırmak için bir soyutlamadır. Herhangi bir şeyin yerine geçmesi beklenmez. x ^ 2 Biçimsel çarpım olarak x * x demek istiyorum. Burada chrisballance.com/wp-content/uploads/2015/10/CRC-Primer.html bu bölümün güzel bir açıklamasını bulabilirsiniz. Cevabımla denediğim şey, bölüm (bu bağlantıda) ile gerçek hesaplama arasındaki boşluğu doldurmaktı
Gabriel Furstenheim
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.