Also known as: TETRA scrambling sequence, TETRA LFSR scrambler
The TETRA scrambler is the linear-feedback shift register
whose pseudo-random output is XORed onto the coded bits of every TETRA logical channel
except the initial BSCH.1 It is an additive scrambler: the transmitter
turns type-4 channel bits into type-5 on-air bits by XOR with a bit sequence p(k), and the receiver
recovers the type-4 bits by XOR with the identical sequence. Crucially the LFSR is seeded by the cell’s
30-bit extended colour code, so a receiver must first learn that
identity — from the unscrambled synchronisation channel — before any other channel becomes readable.2
The generator
The connection polynomial (§8.2.5.2 eq. 8.40) has 14 feedback taps, which GopherTrunk packs into a 32-bit mask so each step is a masked-AND plus a parity:
// internal/radio/framing/scramble_tetra.go — ETSI EN 300 392-2 §8.2.5.
// Taps at i = 1,2,4,5,7,8,10,11,12,16,22,23,26,32.
const scrambleTetraTapMask uint32 = 0x82608EDB
func (s *ScramblerTetra) Next() byte {
v := s.state & scrambleTetraTapMask
bit := byte(popcount32(v) & 1) // new p(k) = XOR of tapped bits
s.state = (s.state << 1) | uint32(bit) // shift left, insert at bit 0
return bit
}
The register is initialised (§8.2.5.2 eq. 8.42) with the extended colour code in its low 30 state bits and
a constant 0xC0000000 fill in the top two (p(−30) = p(−31) = 1); output begins at p(1). For the BSCH
and BSCH-Q the colour-code bits are all zero, so a cold receiver can always descramble the synchronisation
channel with a zero seed.
Two invisible bugs
The scrambler is a cautionary tale in why round-trip tests are not enough (issue #925). Two independent bugs
each broke every real, externally-scrambled burst while passing every synthetic test. First, the LFSR
originally shifted the wrong direction — right, inserting at bit 31 — which reversed the register relative
to the tap convention and diverged from the spec sequence starting at p(2). Second, the 30-bit seed is
carried MSB-first (e(1) in the high bit) but the LFSR wants e(i+1) in state bit i, so the low 30 bits must be
bit-reversed on the way in. Both faults are self-consistent: because scrambling and descrambling share the
same generator, a wrong-but-matching sequence cancels perfectly in any encode-then-decode round-trip, and the
zero-seeded BSCH is a fixed point of bit-reversal. The only symptom was on real air — the receiver would
lock off the unscrambled synchronisation training sequence, yet no BNCH or SCH message would ever decode.
This is the general TETRA trap: validate the scrambled path against a real capture, not just a self-round-trip.
Relevance to SDR
ScrambleTetra / DescrambleTetra are the XOR-symmetric entry points the whole channel stack calls after
colour-code learning. The traffic extractor descrambles each raw
type-5 block before the TCH/S decoder sees it, and the AACH, BNCH, and SCH decoders all descramble first. A
soft-decision variant, DescrambleTetraSoft, applies the same per-bit sign flips to LLRs so soft-decision
decoding works end to end. Getting the tap mask, shift direction, and seed orientation all exactly right is
the difference between a control channel that locks and decodes and one that only locks.
Sources
-
Scrambler — Wikipedia, on additive (synchronous) scrambling by XOR with a pseudo-random sequence. ↩
-
Linear-feedback shift register — Wikipedia, on the register and feedback-polynomial construction the scrambler uses. ↩