use binfield_matrix::{matrix_mul, matrix_mul_systematic};
pub fn encode(data: u16) -> u32 {
assert_eq!(data >> 12, 0);
matrix_mul_systematic(data, CORE_XPOSE)
}
pub fn decode(word: u32) -> Option<(u16, usize)> {
assert_eq!(word >> 23, 0);
let data = (word >> 11) as u16;
let s: u16 = matrix_mul(word, PAR);
let n = s.count_ones() as usize;
if n <= 3 {
return Some((data, n));
}
for (i, &syn) in SYN.iter().enumerate() {
let n = (s ^ syn).count_ones() as usize;
if n <= 2 {
return Some((data ^ 1 << i, n + 1));
}
}
let s: u16 = matrix_mul(rotate_11(word), PAR);
let n = s.count_ones() as usize;
if n <= 3 {
return Some((data ^ s, n));
}
for (i, &syn) in SYN.iter().enumerate() {
let r = s ^ syn;
let n = r.count_ones() as usize;
if n <= 2 {
return if i == 0 {
Some((data ^ r ^ 1 << 11, n + 1))
} else {
Some((data ^ r, 3))
};
}
}
None
}
fn rotate_11(word: u32) -> u32 {
let parity = word & 0x7FF;
word >> 11 | parity << 12
}
const CORE_XPOSE: &[u16] = &[
0b101001001111,
0b111101101000,
0b011110110100,
0b001111011010,
0b000111101101,
0b101010111001,
0b111100010011,
0b110111000110,
0b011011100011,
0b100100111110,
0b010010011111,
];
const PAR: &[u32] = &[
0b10100100111110000000000,
0b11110110100001000000000,
0b01111011010000100000000,
0b00111101101000010000000,
0b00011110110100001000000,
0b10101011100100000100000,
0b11110001001100000010000,
0b11011100011000000001000,
0b01101110001100000000100,
0b10010011111000000000010,
0b01001001111100000000001,
];
const SYN: &[u16] = &[
0b10001110101,
0b10010011111,
0b10101001011,
0b11011100011,
0b00110110011,
0b01101100110,
0b11011001100,
0b00111101101,
0b01111011010,
0b11110110100,
0b01100011101,
0b11000111010,
];
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_rotate11() {
assert_eq!(rotate_11(0b111111111111_00000000000), 0b000000000001_11111111111);
assert_eq!(rotate_11(0b000000000000_11111111111), 0b111111111110_00000000000);
assert_eq!(rotate_11(0b100000000000_00000000000), 0b000000000001_00000000000);
}
#[test]
fn test_encode() {
assert_eq!(encode(0), 0);
assert_eq!(encode(0b111111111111), 0b111111111111_11111111111);
assert_eq!(encode(0b111111000000), 0b111111000000_11001101000);
assert_eq!(encode(0b000000111111), 0b000000111111_00110010111);
assert_eq!(encode(0b100000000001), 0b100000000001_01001001111);
}
#[test]
fn test_decode() {
let w = 0b101010101010;
let e = encode(w);
assert_eq!(e, 0b1010101010_1000101111001);
assert_eq!(decode(e^0b01000000000000000000010), Some((w, 2)));
assert_eq!(decode(e^0b00100000000000000000100), Some((w, 2)));
assert_eq!(decode(e^0b00010000000000000001000), Some((w, 2)));
assert_eq!(decode(e^0b00001000000000000010000), Some((w, 2)));
assert_eq!(decode(e^0b00000100000000000100000), Some((w, 2)));
assert_eq!(decode(e^0b00000010000000001000000), Some((w, 2)));
assert_eq!(decode(e^0b00000001000000010000000), Some((w, 2)));
assert_eq!(decode(e^0b00000000100000100000000), Some((w, 2)));
assert_eq!(decode(e^0b00000000010001000000000), Some((w, 2)));
assert_eq!(decode(e^0b00000000001010000000000), Some((w, 2)));
assert_eq!(decode(e^0b00000000010000000000001), Some((w, 2)));
assert_eq!(decode(e^0b00000000100000000000010), Some((w, 2)));
assert_eq!(decode(e^0b00000001000000000000100), Some((w, 2)));
assert_eq!(decode(e^0b00000010000000000001000), Some((w, 2)));
assert_eq!(decode(e^0b00000100000000000010000), Some((w, 2)));
assert_eq!(decode(e^0b00001000000000000100000), Some((w, 2)));
assert_eq!(decode(e^0b00010000000000001000000), Some((w, 2)));
assert_eq!(decode(e^0b00100000000000010000000), Some((w, 2)));
assert_eq!(decode(e^0b01000000000000100000000), Some((w, 2)));
assert_eq!(decode(e^0b10000000000001000000000), Some((w, 2)));
assert_eq!(decode(e^0b10000000000010000000000), Some((w, 2)));
assert_eq!(decode(e^0b11100000000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b01110000000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b00111000000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b00011100000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b00001110000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b00000111000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b00000011100000000000000), Some((w, 3)));
assert_eq!(decode(e^0b00000001110000000000000), Some((w, 3)));
assert_eq!(decode(e^0b00000000111000000000000), Some((w, 3)));
assert_eq!(decode(e^0b00000000011100000000000), Some((w, 3)));
assert_eq!(decode(e^0b00000000001110000000000), Some((w, 3)));
assert_eq!(decode(e^0b00000000000111000000000), Some((w, 3)));
assert_eq!(decode(e^0b00000000000011100000000), Some((w, 3)));
assert_eq!(decode(e^0b00000000000001110000000), Some((w, 3)));
assert_eq!(decode(e^0b00000000000000111000000), Some((w, 3)));
assert_eq!(decode(e^0b00000000000000011100000), Some((w, 3)));
assert_eq!(decode(e^0b00000000000000001110000), Some((w, 3)));
assert_eq!(decode(e^0b00000000000000000111000), Some((w, 3)));
assert_eq!(decode(e^0b00000000000000000011100), Some((w, 3)));
assert_eq!(decode(e^0b00000000000000000001110), Some((w, 3)));
assert_eq!(decode(e^0b00000000000000000000111), Some((w, 3)));
assert_eq!(decode(e^0b00000000000000000000000), Some((w, 0)));
assert_eq!(decode(e^0b00000000000000000000001), Some((w, 1)));
assert_eq!(decode(e^0b00000000000000000000011), Some((w, 2)));
assert_eq!(decode(e^0b00000000000000000000111), Some((w, 3)));
assert_eq!(decode(e^0b00000001000000000000000), Some((w, 1)));
assert_eq!(decode(e^0b00000011000000000000000), Some((w, 2)));
assert_eq!(decode(e^0b00000111000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b00000100000000000000001), Some((w, 2)));
assert_eq!(decode(e^0b00000110000000000000001), Some((w, 3)));
assert_eq!(decode(e^0b00000100000000000000011), Some((w, 3)));
for w in 0..1<<12 {
assert_eq!(decode(encode(w)), Some((w, 0)));
}
let w = encode(0b110111101110);
for ((i, j), k) in (0..23).zip(0..23).zip(0..23) {
let e: u32 = 1 << i | 1 << j | 1 << k;
let n = e.count_ones() as usize;
assert_eq!(decode(w ^ e), Some((0b110111101110, n)));
}
for (((h, i), j), k) in (0..23).zip(0..23).zip(0..23).zip(0..23) {
let e: u32 = 1 << h | 1 << i | 1 << j | 1 << k;
let n = e.count_ones() as usize;
if n >= 4 {
assert_eq!(decode(w ^ e), None);
}
}
}
}