#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PnScrambler {
taps: u32,
width: u32,
seed: u32,
}
impl PnScrambler {
pub fn new(taps: u32, width: u32, seed: u32) -> Self {
assert!((2..=32).contains(&width), "LFSR width must be in 2..=32");
let mask = Self::mask_for(width);
assert!(seed != 0, "LFSR seed must be nonzero");
assert!(seed & !mask == 0, "LFSR seed must fit in `width` bits");
assert!(taps & !mask == 0, "LFSR taps must fit in `width` bits");
Self { taps, width, seed }
}
#[inline]
fn mask_for(width: u32) -> u32 {
if width == 32 {
u32::MAX
} else {
(1u32 << width) - 1
}
}
pub fn scramble(&self, data: &mut [u8]) {
let mask = Self::mask_for(self.width);
let top = self.width - 1;
let mut reg = self.seed & mask;
for byte in data.iter_mut() {
let mut out = 0u8;
for bit in 0..8 {
let pn = (reg & 1) as u8;
out |= (((*byte >> bit) & 1) ^ pn) << bit;
let fb = (reg & self.taps).count_ones() & 1;
reg = (reg >> 1) | (fb << top);
reg &= mask;
}
*byte = out;
}
}
}