Notes

The register holds r bits

· algorithms

The bit at x^r is congruent to the rest of the generator. The register keeps r bits and XORs that rest when the old top bit was 1.

Last time the shift made one bit past degree rr, and a single XOR with GG cleared it. That extra bit is 11, and the leading coefficient of GG is 11, so their sum is 00. I know the result before I store the bit.

The bit that cancels itself

Take G=10011G=10011, so r=4r=4, and a remainder 10111011 with the next bit 00. This is the first of the four zeros after 101101101101. Last time’s step shifts, sees bit 44, and XORs the whole generator:

10110
^ 10011
-------
00101

Split off the top bit. The generator is x4+g(x)x^{4}+g(x) with g=0011g=0011:

1 0110
^ 1 0011
--------
0 0101

The top line is 1+1=01+1=0. The register only has to keep the low rr bits and, when that cancelled bit was going to be 11, XOR gg.

Whether the shift produces xrx^{r} is decided by the MSB already in the register. The register is rr bits wide, so

Rk(x)=tkxr−1+⋯+a0,tk=[xr−1]Rk.R_{k}(x)=t_{k} x^{r-1}+\cdots+a_{0}, \qquad t_{k}=[x^{r-1}]R_{k}.

tkt_{k} may be 00. It is the coefficient of xr−1x^{r-1} in that fixed width, which is what msb reads. The leading coefficient of RkR_{k} is the highest power that is actually present, and that power may sit lower than xr−1x^{r-1}. One shift moves the coefficient of xr−1x^{r-1} onto xrx^{r}.

Replace the leading power

G(x)=xr+g(x),deg⁡g<r.G(x)=x^{r}+g(x), \qquad \deg g<r.

Since G≡0G\equiv 0,

xr+g(x)≡0(modG),x^{r}+g(x)\equiv 0\pmod{G},

and moving g(x)g(x) across the congruence changes its sign:

xr≡−g(x)(modG).x^{r}\equiv -g(x)\pmod{G}.

In F2\mathbb{F}_2 that minus sign does nothing. The addition table says 1+1=01+1=0, so −1=1-1=1, and the same holds coefficient by coefficient: −g(x)=g(x)-g(x)=g(x). Therefore

xr≡g(x)(modG).\boxed{x^{r}\equiv g(x)\pmod{G}.}

For this generator, x4≡−(x+1)x^{4}\equiv -(x+1) and then x4≡x+1x^{4}\equiv x+1. The two sides differ by GG:

10000
^00011
------
10011

So the update never builds the bit at xrx^{r}. The incoming bit is bk+1b_{k+1}. Reducing modulo xrx^{r} drops every power of degree rr or more, and that is a different operation from rem⁡G\operatorname{rem}_{G}. With this same GG and P=x4+x2P=x^{4}+x^{2},

P mod x4=x2,rem⁡G(P)=x2+x+1.P\bmod x^{4}=x^{2}, \qquad \operatorname{rem}_{G}(P)=x^{2}+x+1.

If tk=0t_{k}=0, then (xRk+bk+1) mod xr(x R_{k}+b_{k+1})\bmod x^{r} is already rem⁡G(xRk+bk+1)\operatorname{rem}_{G}(x R_{k}+b_{k+1}). If tk=1t_{k}=1, add gg:

Rk+1=(xRk+bk+1) mod xr+tk g(x).\boxed{R_{k+1}=(x R_{k}+b_{k+1})\bmod x^{r}+t_{k}\,g(x).}

On the same step, tk=1t_{k}=1 because 10111011 starts with 11. The shift’s low four bits are 01100110, and

0110
^0011
-----
0101

Same remainder as the five-bit XOR.

The program drops the leading 11 of the generator with a mask, appends the rr zero bits as before, and keeps the register inside those rr bits:

// Fixed-width register. `truncated_generator` is `generator` without its
// leading 1, which already sits at bit `width`.
[[nodiscard]] uint32_t register_crc(const std::vector<int>& message_bits,
uint32_t generator) {
const int width = polynomial_degree(generator);
uint32_t crc_register = 0;
std::vector<int> augmented = message_bits;
augmented.resize(augmented.size() + static_cast<size_t>(width), 0);
const uint32_t register_mask = (1U << width) - 1;
const uint32_t truncated_generator = generator & register_mask;
for (const int bit : augmented) {
const uint32_t msb = (crc_register >> (width - 1)) & 1U;
crc_register =
((crc_register << 1) | static_cast<uint32_t>(bit)) & register_mask;
if (msb == 1) {
crc_register ^= truncated_generator;
}
}
return crc_register;
}

msb is [xr−1]Rk[x^{r-1}]R_{k}. truncated_generator is gg. (crc_register << 1) & register_mask, with the new bit in the low place, is (xRk+bk+1) mod xr(x R_{k}+b_{k+1})\bmod x^{r}. The mask is what makes deg⁡Rk<r\deg R_{k}<r true at every step, not only after a reduction. The value is still rem⁡G\operatorname{rem}_{G} of the bits read so far, so the message 101101101101 followed by four zeros still ends at 11101110.

A generator of degree 3232 is 3333 bits long, since the coefficient of x32x^{32} is 11. The familiar constant 0x04C11DB7 is that polynomial with x32x^{32} removed: it is gg, which is all the register stores.

The zeros are still written out at the end of the message. The next step is to fold each message bit into the top of the register and stop appending them.