diff --git a/src/whitener.rs b/src/whitener.rs index 8832616babfdf9d1d75c2833b8fd4b3362f14de1..d5210c5834b3d835205f9eb365b77e736151715f 100644 --- a/src/whitener.rs +++ b/src/whitener.rs @@ -1,11 +1,33 @@ -const WHITE: [u8; 16] = [ - 0xe9, 0xcf, 0x67, 0x20, 0x19, 0x1a, 0x07, 0xdc, 0xc0, 0x72, 0x79, 0x97, 0x51, 0xf7, 0xdd, 0x93, -]; - pub(crate) fn whiten(data: &mut [u8]) { - for (i, d) in data.iter_mut().enumerate() { - *d ^= WHITE[i % 15]; + let mut state = 0xE9CF; + + for d in data.iter_mut() { + let b; + (b, state) = lfsr_byte(state); + *d ^= b; + } +} + +// (byte, state) +fn lfsr_byte(mut state: u16) -> (u8, u16) { + let mut out = 0; + for i in (0..8).rev() { + out |= u8::try_from(state & 1).unwrap() << i; + state = lfsr(state); + } + + (out, state) +} + +// https://en.wikipedia.org/wiki/Linear-feedback_shift_register#Galois_LFSRs +fn lfsr(mut state: u16) -> u16 { + let lsb = state & 1; + state >>= 1; + if lsb > 0 { + state ^= 0xB400; // apply toggle mask } + + state } #[cfg(test)] @@ -25,4 +47,54 @@ mod tests { whiten(&mut data); assert_eq!(orig, data); } + + #[test] + fn test_lfsr() { + let start = 0xACE1; + let end_expected = 0xE270; + + let state = lfsr(start); + + assert_eq!(end_expected, state); + } + + #[test] + fn test_lfsr_byte() { + let start = 0xE9CF; + let (out, state) = lfsr_byte(start); + assert_eq!(0xF3, out); + assert_eq!(0xE3B1, state); + } + + #[test] + fn test_doc_example() { + let start = 0xE9CF; + let expected_out = [ + 0xF3, 0x8D, 0xD0, 0x6E, 0x1F, 0x65, 0x75, 0x75, 0xA5, 0xBA, 0xA9, 0xD0, 0x7A, 0x1D, + 0x1, 0x21, + ]; + + let mut actual_out = [0; 16]; + let mut state = start; + for i in 0..16 { + let (out, ns) = lfsr_byte(state); + state = ns; + actual_out[i] = out; + } + + assert_eq!(expected_out, actual_out); + } + + #[test] + fn test_doc_example_through_whitener() { + let expected_out = [ + 0xF3, 0x8D, 0xD0, 0x6E, 0x1F, 0x65, 0x75, 0x75, 0xA5, 0xBA, 0xA9, 0xD0, 0x7A, 0x1D, + 0x1, 0x21, + ]; + + let mut actual_out = [0; 16]; + whiten(&mut actual_out); + + assert_eq!(expected_out, actual_out); + } }