1

I've iterated of lots of articles - for some reason I couldn't find any which describes what must be a simple procedure: How to combine a calculated CRC with the original message, so that calculating CRC again results in 0 (=checks out as correct)? I did find several examples with 'longhand' calculations (only 2 or 3 bit CRCs), but no example which uses a library function such as [crcmod][1] (Python library).

Here's a simple program I wrote to check it out:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#

import crcmod

def test_cycle():
    test_str = b"123456789"
    orig_msg = test_str
    print("Original message: {:s}".format(orig_msg.hex()))

    #~ crc_calc = crcmod.predefined.Crc('xmodem')
    crc_calc = crcmod.Crc(
                0x11021,
                rev = False,
                initCrc = 0x0000,
                xorOut = 0x0000)

    crc_calc.update(orig_msg)
    print("CRC: {:04x}".format(crc_calc.crcValue))

    lo = crc_calc.crcValue & 0xff
    hi = crc_calc.crcValue >> 8
    new_msg = test_str + bytes((hi, lo))
    print("Crc appended: {:s}".format(new_msg.hex()))

    crc_calc.update(new_msg)
    print("CRC: {:04x}".format(crc_calc.crcValue))


def main(args):
    test_cycle()
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

There are some commented lines, from experiments with different byte ordering. The results from the program are:

Original message: 313233343536373839
CRC: 31c3
Crc appended: 31323334353637383931c3
CRC: 00ef

The first CRC (31C3) seems to check out with correspond with the expected values for xmodem-CRC. I tried, in many ways, to combine the obtained CRC with the original string, but never obtain '0'. Am I missing something here?

jcoppens
  • 5,306
  • 6
  • 27
  • 47
  • I don't know your Python module but my own Pascal library gives a CRC 0 for `31323334353637383931C3`, verified by https://www.lammertbies.nl/comm/info/crc-calculation.html. – gammatester Jul 06 '18 at 07:26
  • @gammatester - the confusion was on my side. I didn't expect the CRC class' method `update` to append. – jcoppens Jul 06 '18 at 16:35

2 Answers2

2

crc_calc.update(new_msg) adds the entire content of new_msg to the CRC. Since crc_calc already holds the result of 313233343536373839, you are effectively calculating the CRC of 31323334353637383931323334353637383931c3 and this is indeed 00ef.

To add only the two bytes to the calculation, use

crc_calc.update(bytes((hi, lo)))

Alternatively, use a new instance of crcmod.Crc(), or reset the crcValue of the existing instance before doing a new calculation

crc_calc.crcValue = 0
crc_calc.update(new_msg)

Both will give you a result of 0

Adrian W
  • 4,563
  • 11
  • 38
  • 52
2

Some background for those arriving at this question, wondering about appending CRCs.

If a CRC is properly appended to the message that it is the CRC of, and there are no errors introduced in the message or CRC, the the CRC of that whole thing will be a constant dependent only on the definition of that CRC.

To properly append the CRC requires care in the bit ordering. For the generic CRC definition afforded by crcmod, if rev is false, then the bits must be appended most significant first. If rev is true, then the bits must be appended least significant first. For byte-oriented messages, this means first off that the width of the CRC has to be a multiple of eight bits (which by the way is all that crcmod permits), and that the CRC be appended in big-endian order or little-endian order respectively.

The resulting constant is not always zero, depending on the definition of the CRC. It is zero if the xorOut value for the CRC is zero. Otherwise the constant is the CRC of n zero bits, where n is the width of the CRC, and where the initial CRC value provided is zero (not initCrc). As an example, for the standard CRC-32, the CRC-32 of a message with its CRC-32 appended in little-endian order is always 0x2144df1c.

For this particular question, the CRC is appended in big-endian order, so 31 c3, and CRC of the resulting message + CRC is then zero.

Mark Adler
  • 101,978
  • 13
  • 118
  • 158
  • The explanation is that the bit holding the _coefficient of the highest exponent_ must always come first. When `rev` is False, the polynomials are represented using the bit whose integer value is 2^0 for the coefficient of X^0 and the coefficient of X^(n-1) goes into the bit 2^(n-1). So, the byte containing that bit comes first. When `rev` is True, the bit 2^(n-1) is used for the coefficient of X^0 and the coefficient of X^(n-1) goes into the bit 2^0. So, in that case, LSB comes first. See [What is the correct byte order for transmitting the computed CRC](https://aweiler.com/crc/crcnaq.html). – Adrian W Jul 09 '18 at 08:22