One byte, then eight shifts
· algorithms
The register still holds rem_G of x^r times the prefix. I XOR the next byte into the top eight bits, then apply T_G eight times.
Last time, after message bits, the register held
and one new bit entered at :
is defined for polynomials of degree less than . The input now comes in bytes. I still want this . XOR the next byte into the top eight bits, then apply eight times, and the register should be eight bits further on.
The prefix grows by a byte
The bits are still , high bit first. Byte , for , is bits through :
The first of those bits sits on . The byte is , which is when it is the first byte.
One bit grew the prefix by . Eight bits, from a prefix whose length is a multiple of eight, are that same growth:
The byte meets the top of the register
is the same remainder on the longer prefix:
and differ by a multiple of , so times either of them has the same remainder. Adding keeps that:
A byte fits in the register when . Then , and both terms carry :
, so uses degrees through : the top eight coefficients. Adding it to is the XOR of the byte into those bits.
Eight times
Last time a single step was
msb reads of the register. (crc_register << 1) & register_mask is . When that coefficient is , XOR , which is truncated_generator. On the byte is already in the polynomial, so these eight steps only multiply by and reduce.
Applied times, multiplies by and reduces:
The case is the definition of . If the formula holds for , then and differ by a multiple of , so
Eight applications give the remainder above:
Byte boundaries
The message is a sequence of bytes. At each multiple of eight bits the register is .
The empty prefix is , and the register starts at . Byte replaces by , which is .
During those eight steps the register began as
so . already holds bits a one-bit loop would still be waiting to read. It is the register between byte boundaries. Once the byte has been fully shifted, the register is again.
After the last byte, is the whole message and the register is the CRC,
That last byte enters as for the last . Eight applications of turn it into .
One byte, two registers
Take , so and . The message is the single byte , and .
Here , so the top eight bits are the whole register and .
The left column feeds that byte through last time’s update, one bit at a time: each bit is . The first bit is , the top of is , the feedback is , and XOR with after the shift leaves .
The right column XORs the byte in before any application of . The first one reads a top coefficient of , so is XOR’d with :
01101100^00000111---------01101011| Steps | Bit by bit | Byte XOR’d in first |
|---|---|---|
| 0 | 00000000 | 10110110 |
| 1 | 00000111 | 01101011 |
| 2 | 00001110 | 11010110 |
| 3 | 00011011 | 10101011 |
| 4 | 00110001 | 01010001 |
| 5 | 01100010 | 10100010 |
| 6 | 11000011 | 01000011 |
| 7 | 10000110 | 10000110 |
| 8 | 00001011 | 00001011 |
For most of those steps the two registers hold different bits. After eight steps both hold . That is , the CRC of this byte.
The program
The loop is the boxed update. The assert is , the same bound as . top_byte_shift is that exponent.
// One byte at a time. The byte is mixed into the top 8 bits, then the// register shifts once per bit. `width` must be at least 8.[[nodiscard]] uint32_t byte_crc(const std::vector<uint8_t>& bytes, uint32_t generator) { constexpr int kBitsPerByte = 8; const int width = polynomial_degree(generator); assert(width >= kBitsPerByte); uint32_t crc_register = 0; const uint32_t register_mask = (1U << width) - 1; const uint32_t truncated_generator = generator & register_mask; const auto top_byte_shift = static_cast<unsigned>(width - kBitsPerByte);
for (const uint8_t byte : bytes) { crc_register ^= static_cast<uint32_t>(byte) << top_byte_shift; for (int bit_index = 0; bit_index < kBitsPerByte; ++bit_index) { const uint32_t msb = (crc_register >> (width - 1)) & 1U; crc_register = (crc_register << 1) & register_mask; if (msb == 1) { crc_register ^= truncated_generator; } } }
return crc_register;}| In the formula | In the program |
|---|---|
byte | |
byte << top_byte_shift | |
the XOR into crc_register | |
| of the register | msb |
(crc_register << 1) & register_mask | |
truncated_generator | |
| one pass of the inner loop | |
| eight passes | |
return crc_register |