4

I have been working on understanding CRC calculations for implementation in VHDL. Specifically I have implemented the CRC-32C (polynomial = 0x1EDC6F41) a couple of ways. First using an LFSR approach and secondly using a lookup table for speed. Everything seems to agree with the online checkers but I am having trouble understanding why, if you calculate a CRC of some data, append the CRC to the end of the data and then recalculate the CRC, I do not get a result of zero.

For example, if I calculate the CRC of the string "123456789" (hex values 313233343536373839) I get a result from the calculator of E3 06 92 83.

Now if I calculate the CRC of 313233343536373839 E3069283 the resulting calculated CRC is BA F5 57 BE; I was expecting this to be zero.

If I repeat the same procedure above with any other of the 8 & 16 bit CRCs available on the calculator I do get zero returned.

FYI, I have been using this calculator for reference.

Also, for anyone else struggling on this topic here are some useful links:

JYelton
  • 32,302
  • 33
  • 134
  • 249
Eanema
  • 41
  • 2
  • 3
    What is the question? – JYelton Jul 26 '19 at 20:01
  • I've done basic CRC checking for serial comms but I never thought that the CRC of the message and CRC should result in zero. Rather, I thought that the receiver would run the CRC calculation again on the message (without the CRC) and compare the two. Why do you think the CRC of the message + CRC should result in zero? – Transistor Jul 26 '19 at 20:05
  • Have you verified by any other means that the calculator is correct for CRC-32C? Have you asked the creator of the calculator? – Elliot Alderson Jul 26 '19 at 20:05
  • @Transistor In theory, it should. For something in hardware, it may be easier to run a bit more data through the CRC and get an easy comparison than comparing a register value. – W5VO Jul 26 '19 at 20:42
  • @Transistor because if you have a result of CRC calculation in the shift register (without post inversion) and finally feed the same bit pattern back into the algorithm, it means all one bits get bitwse XORed to 0 thus result is always zero. However if the result was post-inverted then feeding it back will produce a constant check value. I think this is the issue of OP. – Justme Jul 26 '19 at 23:12

3 Answers3

5

If you correctly append a CRC to the message it was calculated from, then the CRC of that whole thing will always be the same constant for that particular CRC definition. However, that constant is zero only for some CRC definitions. In particular, those whose final exclusive-or is zero.

For the CRC-32C, that constant is 0x48674bc7. To correctly append the CRC, the bytes must be in little endian order -- the opposite of what you tried. That is because CRC-32C processes the least significant bits of the message first.

Mark Adler
  • 226
  • 2
  • 5
3

A result of zero is only expected for some calculation methods.

Besides the polynomial and byte ordering, there are other options for the various CRC methods.

  1. The initial pattern.
  2. If the CRC is inverted before transmission.
  3. How padding is done for unaligned sizes.

I had some good CRC references, but unfortunately, I didn't take all of them with me when I retired. Even so, I can make the CRC-32 option work as you expect if I invert the CRC.

Using the calculator, use 12345678 ASCII (multiple of 32-bits, so no issue with padding). Then, invert the CRC result before appending it to the starting data pattern. Run the calculation again, the result is FFFFFFFF. The inversion is zero, what you expect. (I only tested with big-endian)

I was disappointed that the wikipedia article barely mentions the 3 options I noted above.

Mattman944
  • 13,638
  • 1
  • 19
  • 43
1

In java, I used:

    String baseline = "123456789";
    byte[] bytes = baseline.getBytes(StandardCharsets.UTF_8);
    CRC32 crc = new CRC32();
    crc.update(bytes);
    int crcq = (int)crc.getValue();
    crc.reset();

    byte[] trail = intToByte(reverseBytes(~crcq));

    byte[] output = concatenate(bytes, trail);   

    crc.update(output);                 // will be 0xffffffff
    int crc4 = ~(int)crc.getValue();    // will be zero

Although this was a java solution, not VHDL, the concept is similar. That is, complement the bits in the message crc and reverse the bytes. When this is appended to the message: 3132333435363738397c6df91c and using the OP's online crc calculator,the result is 0xffffffff. Complementing the bits again yields the expected answer of zero. Perhaps the code should have been posted in a java forum and not here.

bobford
  • 11
  • 2
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 03 '23 at 06:15