crcutil
When communicating with hardware devices like integrated circuits, often CRC sums need to be calculated with polynomials of orders lower than 32, like 3, 4, 6, 8 or 16. Sometimes the so-called reflected form of algorithms has to be used on the wire, sometimes the normal form -- or even both forms in the same protocol; in some cases obscure additional reflections need to be performed.
As the Go standard library offers no support for these smaller widths of CRCs -- also its crc32 implementation implements solely the commonly used reflected form of the algorithm, and does not provide a generic way to specify initial values or final XORing --, this module tries to provide that functionality in a generic way.
Using the type Poly, a polynomial may be specified by its word value and bit width,
and whether the word refers to the normal, reflected, or a reciprocal representation.
A value of type Poly may be converted to other representations, e.g. from normal to reflected form, using the corresponding method.
From a Poly, a lookup table may be created that may be used directly, if the amount of data is very small, like e.g. in case of a CRC-3.
A Model specifies a CRC algorithm: the polynomial,
the initial value (resp. optional initial inversion) to be used,
and whether a final operation like inversion (XORing) shall be applied. From a static Model,
an Inst may be created that allows to calculate a checksum over an amount of data.
There exist sub-packages poly{n} and crc{n}
that provide concrete versions of the generic Poly and Model types for some common values of bit widths and word types.
One example for a predefined Model is crc8.SAEJ1850, which uses poly8.SAEJ1850 with initial and final bitwise inversion. Another example is crc16.Modbus, based on the reversed form of poly16.IBM.
Example
As a real example, the LED driver circuit Infineon TLD7002-16ES uses both a CRC-3 in reflected form and a CRC-8 (SAEJ1850) in normal form in the same serial protocol.
CRC-3
The CRC-3 polynomial x3 + x1 + 1 (GSM, value = 0b11 = 3) can be created in the following equivalent ways:
p := poly3.New(0b11) // 0b11 = 21 + 2deg
p := &poly8.Poly{Word: 0b11, Width: 3}
p := &Poly[uint8]{Word: 0b11, Width: 3} // using the generic type
Since the 3-bit polynomial can be represented by an 8-bit value,
the poly3 internally uses poly8.Poly,
like shown in the third line above.
If we wanted to create a lookup table for five bits of data, with an initial value of 5 -- as defined by the specification -- encoded into the table, we could write
tab := p.MakeTable(crcutil.WithInitialValue(5), crcutil.WithDataWidth(5))
To get the CRC-sum of a 5-bit value of 13 it would be sufficient to
evaluate tab[13].
For more details see the example for func (*Poly[T]) MakeTable() in the documentation.
CRC-8-SAE-J1850
To calculate a checksum over some bytes using the SAE-J1850 polynomial x8 + x4 + x3 + x2 + 1, follow this example (compare the result the one listed at AUTOSAR Specification of CRC Routines, p.24):
crc := crc8.SAEJ1850.New()
// insert some bytes
crc.Write([]byte{0xF2, 0x01, 0x83})
fmt.Printf("0x02x\n", crc.Sum())
// => 0x37
Implicit +1 notation
Functions FromImplicit1Notation and FromImplicit1NotationReciprocal
create a Poly from a polynomial word in Koopman's implicit +1 notation,
which may be helpful when using polynomials with specific Hamming Distance
properties from the tables provided by Philip Koopman.
hash.Hash interface
For an implementation aligned with Go's hash.Hash interface, see github.com/knieriem/hash, which is a thin wrapper
around crcutil.