A fixed shift of the growing prefix
· algorithms
r is the degree of G, and it stays fixed while the prefix grows. The register holds that prefix times x^r, and the value is the CRC only when the prefix is the whole message.
Last time the register stayed bits wide, and the loop still read the message followed by zeros. Appending them made the input longer and added iterations. Those zeros are a fixed factor . I put that factor into the polynomial the register holds, and the input stays the message.
A heavier state
After message bits, is that prefix. Last time the register held , so zeros still had to be shifted in afterwards. The width of that shift is . It stays fixed while the prefix grows. This time the register holds the prefix already multiplied by that fixed power:
Degree less than is part of that remainder, so . It is the bits so far, followed by the same zeros. It becomes the CRC when the prefix has grown into the whole message, and not before.
The empty prefix is . The register starts at , and satisfies the same relation.
The next bit is , so the prefix grows by
The register has to apply the same fixed shift to the longer prefix:
The remainder replaces by , and
Two contributions to
still fits in the register. Split off the coefficient of :
may be . It is that fixed coefficient, the bit msb reads. The leading coefficient of is whichever highest power is actually nonzero, and it may sit below .
One factor of lifts the coefficient of just past the register,
The new bit produces the same power, because the state already includes the that last time was written as trailing zeros. The two coefficients add:
In that sum of coefficients is an XOR. Call it the feedback,
It multiplies , so it sits one bit past the register: bits in all. Last time , and that congruence is what keeps the step inside the register. The overflow is congruent to , which already fits in bits. Once has moved out, the powers below are
Since , that product already has degree less than . It is the register after (crc_register << 1) & register_mask. Therefore
The two terms are written in that order. First store . Then, when , XOR . The incoming bit never enters the low end. It only joins in .
When and are both , the two coefficients cancel and . The arriving bit is spent on the bit that just left, and stays out.
The same step is one multiplication by after the new bit has been added at . For a polynomial of degree less than ,
The split is that operator. The coefficient of decides whether is added, and is the rest:
Adding at makes that coefficient , and the lower part stays , so
Example
Take , so and . The message is , and . The register starts at . These six bits are the whole input.
The first bit is . The top is , so the feedback is . Shifting leaves , and the bit arrives as :
0000^0011-----0011The second bit is . The top is , the feedback is , and shifts to .
The third bit is . The top is , the feedback is , and shifts to :
1100^0011-----1111The fourth bit is , and the top is already . The feedback is . Shifting gives , and is not added. This is the cancellation: both sources of were present, and they removed each other.
The fifth bit is . The top of is , the feedback is , the shift is , and the XOR with leaves .
The sixth bit is . The top is again, so the feedback is , and the shift takes to .
Every message bit is in, so and
The register reads . The input was the six message bits, and the loop ran six times.
The program
msb is . feedback is , written with ^. truncated_generator is . (crc_register << 1) & register_mask is . The incoming bit enters only through feedback. The masked shift plus that conditional XOR is .
// Same register as register_crc. The incoming bit is mixed into the outgoing// msb, so the message is not padded with `width` zeros.[[nodiscard]] uint32_t feedback_crc(const std::vector<int>& message_bits, uint32_t generator) { const int width = polynomial_degree(generator); uint32_t crc_register = 0; const uint32_t register_mask = (1U << width) - 1; const uint32_t truncated_generator = generator & register_mask;
for (const int bit : message_bits) { const uint32_t msb = (crc_register >> (width - 1)) & 1U; const uint32_t feedback = msb ^ static_cast<uint32_t>(bit); crc_register = (crc_register << 1) & register_mask; if (feedback == 1) { crc_register ^= truncated_generator; } }
return crc_register;}