Also known as: P25 RS codes, RS(24,12,13), RS(36,20,17), GF(64) Reed-Solomon
The P25 Reed-Solomon codes are three shortened Reed-Solomon codes over the finite field GF(2⁶) that TIA-102.BAAA-A §5.9 uses as the outer FEC on P25’s most valuable fields.1 They protect the Link Control word, the Encryption Sync, and the Header Data Unit — sitting on top of an inner Hamming/Golay layer to correct the residual symbol errors that survive it. GopherTrunk decodes all three with the classic pipeline: Berlekamp-Massey for the error-locator polynomial, a Chien search for the error positions, and Forney’s algorithm for the magnitudes.2
The three codes
Each code is shortened from the natural RS(63, K, D) form by deleting leading information
symbols, and all three share one field: GF(2⁶) generated by the primitive polynomial
α⁶ + α + 1. Elements are 6-bit values where bit i is the α^i coefficient, α is 0b000010,
and since α⁶³ = 1 a log/exp table makes multiplication and inversion single lookups. The three
codes differ only in dimensions and role:
| Code | K | N | D | t | Role in P25 |
|---|---|---|---|---|---|
| RS(24,12,13) | 12 | 24 | 13 | 6 | Link Control word (LCW); Phase 2 SACCH outer FEC |
| RS(24,16,9) | 16 | 24 | 9 | 4 | Encryption Sync (MI + ALGID + KID); Phase 2 FACCH |
| RS(36,20,17) | 20 | 36 | 17 | 8 | Header Data Unit (HDU) |
Encoding is systematic: the K information symbols pass through verbatim, and the R parity symbols are the information vector times the right-hand parity columns of the spec’s generator matrix. GopherTrunk stores those matrices directly from §5.9 in the octal form the spec prints:
// TIA-102.BAAA-A §5.9 "GLC matrix", from internal/radio/framing/rs_gf64.go
// Right-hand 12×12 parity sub-matrix for RS(24,12,13); octal = 6-bit GF(2⁶) elems.
var rsParity24_12 = [12][12]byte{
{0o62, 0o44, 0o03, 0o25, 0o14, 0o16, 0o27, 0o03, 0o53, 0o04, 0o36, 0o47},
// … 11 more rows (GES and PHDR matrices likewise) …
}
How the decode works
The decoder treats the received codeword as a polynomial and evaluates it at the generator’s roots α¹…α^R to get R syndromes — all zero means the word is already valid. Berlekamp-Massey synthesises the shortest LFSR (the error-locator polynomial Λ) that generates the syndrome sequence; if its degree exceeds t = R/2 the word is uncorrectable and returned as such. A Chien search evaluates Λ across the field to find the error positions, and Forney’s formula computes each error magnitude from the error-evaluator and the formal derivative of Λ. GopherTrunk then re-computes the syndromes on the corrected word as a defensive check, so a genuine >t error pattern that happens to yield a low-degree locator is rejected rather than returned as a plausible-but-wrong codeword.
Relevance to SDR
internal/radio/framing/rs_gf64.go builds the GF(2⁶) field once at init and exposes
EncodeRS…, VerifyRS…, and DecodeRS… for all three codes. These are what turn a marginally
decoded voice frame into a trustworthy one: after the inner Hamming(10,6,3)
layer fixes single-bit errors, the RS layer corrects whole symbols the Hamming pass missed —
without it, residual bit errors corrupt the talkgroup and source in a
Link Control word under low SNR, ending calls early. The same GF(2⁶) codes are reused by
P25 Phase 2 as the outer FEC over its SACCH/FACCH channels.
Sources
-
Reed-Solomon error correction — Wikipedia, on the symbol-oriented block codes P25 uses over GF(2⁶). ↩
-
Berlekamp-Massey algorithm — Wikipedia, on the error-locator synthesis at the heart of the decoder. ↩