Cyclic Codes: CRC, BCH & Reed–Solomon
Cyclic codes turn shifts into polynomial algebra: a CRC uses the remainder to detect corruption, while BCH and Reed–Solomon codes use structured roots and syndromes to locate and correct errors. This entry derives the common machinery, works a CRC exactly, and makes every field, polynomial, shortening, and byte-order convention explicit.
A cyclic code is a linear block code whose legal words remain legal after a cyclic shift. That symmetry turns an -symbol vector into a polynomial modulo , so encoding, checking, and much of decoding become polynomial arithmetic over a finite field. CRCs, BCH codes, and Reed–Solomon (RS) codes share this machinery, but they solve different problems: a CRC is normally a high-quality detector, while BCH and RS spend more redundancy and decoder work to correct errors.
The family name is not an on-wire specification. Field construction, generator polynomial, coefficient order, initialization, reflection, shortening, symbol order, and final XOR all affect the transmitted bits. Interoperability starts with those conventions, not with the label “CRC-32” or “RS(255,223).”
Vectors become polynomials #
Represent a word by
Multiplication by shifts every coefficient. Reducing modulo wraps the coefficient of back to the constant position, exactly implementing a cyclic shift. A cyclic code over is generated by a monic polynomial that divides :
If , the code has information symbols and check symbols. The complementary polynomial
plays the parity-check role. This is the same relationship described for linear block codes, written in a basis where shifting has algebraic structure.
flowchart TD
M["message polynomial"] --> E["systematic encode<br/>append places → divide by g(x) → add remainder"]
E --> C["codeword divisible by g(x)"]
C --> CH["noisy channel"]
CH --> S["compute remainder or root syndromes"]
S --> Z{"all zero?"}
Z -->|yes| OK["accept as codeword"]
Z -->|no| ACT["detect, or locate and correct"]
The diagram deliberately ends in two actions. A nonzero syndrome proves that the received word is outside the code, but a detector may stop there; a corrector needs enough independent syndrome information to identify an error pattern uniquely.
Systematic encoding is polynomial division #
To keep the message visible, shift it by positions and divide by :
Over subtraction and addition are both XOR, so the systematic codeword is
It is divisible by . At the receiver, polynomial division of by produces a zero remainder for every legal codeword and a nonzero remainder for most corrupted words. “Most” matters: an error polynomial that is itself divisible by is undetected.
Worked CRC division #
Use message 1101, interpreted highest power first as
and generator 1011,
The generator has degree three, so append three zeros: 1101000. XOR long division gives remainder 001; append that remainder to obtain 1101001. Dividing the complete seven-bit word by 1011 gives zero.
The same calculation can be implemented as a three-stage linear-feedback shift register. The register is only a streaming form of polynomial division; its tap drawing must still match the chosen coefficient and shift convention.
A degree- CRC with nonzero constant coefficient detects every single burst of length at most . A burst shorter than or equal to has an error polynomial with and nonzero end coefficients; a degree- generator with no factor cannot divide it. Other guarantees depend on the polynomial and protected length. If divides , every odd-weight error is detected; that benefit is bought by constraining the generator and is not implied by its degree alone.
A CRC is a parameter tuple #
RFC 1662 provides a concrete interoperability lesson. Its 16-bit FCS is built from the polynomial , but the specification also fixes the initial value, complementing, least-significant-bit-first transmission, and a receiver residue check. An implementation that copies only 0x1021 can produce the wrong octets while believing it uses the same polynomial.
Record at least:
- width and full mathematical polynomial;
- initial register value;
- input and output reflection conventions;
- final XOR/complement;
- byte order on the wire;
- protected byte range, including or excluding headers and the check field;
- a normative check value and the expected residue after processing a complete valid frame.
The CRC should be checked after the transforms the protocol declares part of its protected word. Descrambling, de-stuffing, byte unescaping, and FEC decoding can sit on either side of the check in different protocols; guessing the order produces consistent false failures.
BCH codes design roots, not just a remainder #
Let be an element of an extension field and let the code length be compatible with its multiplicative order. A narrow-sense BCH code with designed distance chooses a generator whose roots include
Because coefficients may live in the base field while those roots live in an extension, is the least common multiple of the roots' minimal polynomials. The BCH bound guarantees
For a binary code designed to correct errors, a common choice is . The actual distance may be larger, but the designed distance is the guaranteed construction parameter.
For received polynomial , evaluate root syndromes
because every legal vanishes at the specified roots. A practical algebraic decoder then follows a causal chain:
- compute the syndromes; all zero means no error is visible to the code;
- solve the key equation for an error-locator polynomial, commonly with Berlekamp–Massey or the extended Euclidean algorithm;
- perform a Chien search over field locations to find the locator roots;
- compute error magnitudes, commonly with Forney's formula; in a binary BCH code each nonzero magnitude is simply one;
- correct, then recompute every syndrome before releasing the word.
If the locator degree, number of roots, or post-correction syndrome is inconsistent, declare decoding failure. Silently applying a partial correction turns a detectable codeword failure into plausible corrupted payload.
Reed–Solomon moves from bits to symbols #
An RS message is a polynomial of degree below over . Evaluate it at distinct field points:
Two different degree- polynomials can agree at no more than points, so their codewords differ in at least
positions. RS meets the Singleton bound and is therefore maximum-distance separable (MDS). With parity symbols it can recover any mixture satisfying
where is the number of unknown erroneous symbols and the number of erasures at known locations.
This distance is measured in field symbols, not bits. In an RS code over , one wrong bit and eight wrong bits inside the same byte both consume one erroneous-symbol position. A physical burst that crosses byte boundaries can consume several positions, while interleaving can spread a long channel burst across different codewords.
Shortening, puncturing, and erasures are different #
- Shortening
- Fix selected information positions to known values, omit them on the wire, and restore them before decoding. Both $n$ and $k$ shrink by the same amount, so the parity count and designed distance are retained.
- Puncturing
- Omit selected transmitted parity symbols and restore them as erasures. The effective rate rises and correction margin falls.
- Erasure decoding
- Transmit the symbol, but let the receiver mark its location unreliable. The decoder spends one distance unit rather than two because it no longer needs to discover the position.
Conflating these operations causes off-by-one and alignment bugs. A shortened RS decoder may expose a full-length API, but the caller must insert the implicit symbols in the exact declared locations. A punctured symbol must enter as zero information, not as a confident numeric zero.
Choose the decoder for the failure model #
| Mechanism | Natural unit | Primary job | Strongest fit | Characteristic limitation |
|---|---|---|---|---|
| CRC | bit polynomial | detection | frames that can be discarded or retransmitted | no correction; guarantee depends on polynomial and length |
| binary BCH | bit | bounded correction | random bit errors, memories, control blocks | field arithmetic and decoder complexity grow with |
| Reed–Solomon | multi-bit symbol | bounded symbol correction/erasure recovery | bursts, storage, concatenated links | one bad bit consumes a whole symbol position |
A CRC after FEC is not redundant. The algebraic decoder corrects patterns within its guaranteed radius and may miscorrect patterns outside it; an independent CRC sharply reduces the chance that an out-of-radius output is accepted. Conversely, a CRC alone is often the right answer when a fast retransmission path exists and permanent FEC overhead would cost more than rare retries.
Bit-exact verification #
Before running a random BER campaign, build small deterministic evidence:
- state the field size and primitive polynomial, then enumerate multiplication and inverses against a reference;
- state polynomial coefficient order and map the first and last wire bits to powers of ;
- encode all-zero, one-hot, all-one, and a published check vector;
- verify the systematic payload positions and complete-codeword residue;
- inject every single error position, then boundary mixtures with and one step beyond;
- confirm that a declared failure leaves no partially corrected payload marked valid;
- test shortening, interleaving, and puncturing boundaries independently before composing them;
- record decoder syndromes, locator degree, root count, corrected positions, and post-check residue for every failed frame.
| Failure signature | First suspect |
|---|---|
| every codeword fails, including a published vector | coefficient order, reflection, init/final XOR, or protected range |
| zero-error words pass but single-error correction points to the wrong location | symbol numbering or Chien-search index mapping |
| only shortened profiles fail | implicit-symbol insertion side or full-length position mapping |
| correction works until erasures are supplied | erasure locator convention or counting incorrectly |
| isolated errors work but bursts overwhelm one codeword | missing or misaligned interleaver |
| decoder reports success but an outer CRC fails | beyond-radius miscorrection, wrong post-check order, or stale decoder state |
The durable mental model is one algebra with three contracts: divisibility defines legal cyclic words, roots and syndromes make error patterns observable, and the protocol parameter tuple maps that algebra to actual bits and bytes. Most theory bugs are distance mistakes; most deployed bugs are convention mistakes.