Field Guide · algorithm

Also known as: IMBE PRBS, IMBE whitener, IMBE descrambler

The IMBE scrambler is the whitening layer of P25 Phase 1 voice channel coding (TIA-102.BABA §7.4): it XORs a 114-bit pseudo-random bit sequence onto six of the eight coded vectors so the transmitted spectrum stays flat and free of the periodic patterns that a raw FEC-coded voice frame would otherwise radiate.1 The keystream comes not from a shift register but from a small 16-bit linear-congruential generator whose seed is derived from the frame’s own u_0 vector, so no side channel is needed to synchronise the two ends.2

u0 data× 16 LCG · state×173 +13849 mod 65536 u1–u6 ⊕ keystream u0, u7 (unscrambled) bit 15
The u0 data value (×16) seeds a 16-bit LCG whose high bit forms a 114-bit keystream XORed onto u1–u6; u0 carries the seed and u7 is unprotected, so both stay in the clear.

How it works

The generator is a textbook linear-congruential recurrence over a 16-bit state: state = (173 · state + 13849) mod 65536. Each iteration’s high bit (bit 15) is taken as one keystream bit. The state is seeded with the 12 Golay data bits of u_0 multiplied by 16 (equivalently, shifted left four places). The recurrence is run 115 times: the first value holds the seed itself and the next 114 supply exactly one scrambling bit per scrambled channel bit — 23 bits each for u_1, u_2, u_3 and 15 bits each for u_4, u_5, u_6, totalling 114.

func PRBS(seed uint16) [114]byte {
    const mul, inc, mod uint32 = 173, 13849, 65536
    state := uint32(seed)
    var bits [114]byte
    for i := 0; i < 114; i++ {
        state = (mul*state + inc) % mod
        bits[i] = byte(state >> 15) // high bit of the 16-bit state
    }
    return bits
}

Two vectors are deliberately left in the clear. u_0 carries the seed, so it must be readable before descrambling begins; u_7 is the unprotected least-sensitive group and is passed through untouched. Within each scrambled vector the keystream is applied from the highest column down to column 0, matching the reference order. The very first generator output (pr[0], the raw seed) is not used as a scrambling bit — it is consumed to advance the state — which is why 115 iterations yield 114 keystream bits. Because XOR is its own inverse, the same routine both scrambles (on encode) and descrambles (on decode) — the two names in the code exist only for readability, and a clean frame satisfies Scramble(Scramble(x)) == x.

The whitening it provides is spectral, not cryptographic. A raw FEC-coded voice frame contains long runs and repeating structure that would concentrate transmit energy into spectral lines; XORing a pseudo-random sequence over the coded bits flattens the spectrum so the modulated signal occupies its channel evenly, which eases carrier recovery and reduces adjacent-channel interference.

Seed integrity

The scrambler couples tightly to the FEC layer through the u_0 seed, and that coupling is the thing to get right. A single bit error in u_0 would shift the seed, produce a completely different 114-bit keystream, and corrupt the descramble of every one of u_1u_6 at once. GopherTrunk therefore runs u_0’s Golay decode first, deriving the seed from the corrected 12-bit value rather than the raw channel bits, exactly as mbelib runs its u_0 ECC before the demodulation step. The full u_0 codeword is then re-decoded from the untouched bits so the error telemetry still reflects the real channel condition. This is a scrambling function for spectral whitening only, not encryption: the algorithm and its constants are public, so it protects nothing — encrypted P25 applies a separate keystream on top.

Relevance to SDR

Distinct from a linear-feedback shift register, which whitens by feedback taps, IMBE uses a multiply-and-add LCG — but the receiver’s job is the same: regenerate the identical keystream locally and XOR it back off. In GopherTrunk the descramble sits between the deinterleaver and the per-vector FEC decode: the full receive order is deinterleave → derive u_0 seed → descramble u_1u_6 → FEC decode. Get the seed derivation or the column order wrong and the downstream Golay/Hamming decode sees noise, so the scrambler, though only a page of arithmetic, sits squarely on the voice critical path.

Sources

  1. Scrambler — Wikipedia, on additive whitening scramblers that flatten a transmitted spectrum. 

  2. Linear congruential generator — Wikipedia, on the multiply-add pseudo-random recurrence used to build the keystream. 

See also