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 >> 24, 0);
let data = (word >> 12) as u16;
let s: u16 = matrix_mul(word, PAR_ALT);
let n = s.count_ones() as usize;
if n <= 3 {
return Some((data ^ s, n));
}
for &q in CORE_XPOSE.iter() {
let syn = s ^ q;
let n = syn.count_ones() as usize;
if n <= 2 {
return Some((data ^ syn, n + 1));
}
}
let s: u16 = matrix_mul(word, PAR);
let n = s.count_ones() as usize;
if n <= 3 {
return Some((data, n));
}
for (i, &q) in CORE.iter().enumerate() {
let syn = s ^ q;
if syn.count_ones() <= 2 {
let err = 1 << 11 >> i;
return Some((data ^ err, 3));
}
}
None
}
const CORE: &[u16] = &[
0b110001110101,
0b011000111011,
0b111101101000,
0b011110110100,
0b001111011010,
0b110110011001,
0b011011001101,
0b001101100111,
0b110111000110,
0b101010010111,
0b100100111110,
0b100011101011,
];
const CORE_XPOSE: &[u16] = &[
0b101001001111,
0b111101101000,
0b011110110100,
0b001111011010,
0b000111101101,
0b101010111001,
0b111100010011,
0b110111000110,
0b011011100011,
0b100100111110,
0b010010011111,
0b110001110101,
];
const PAR: &[u32] = &[
0b101001001111100000000000,
0b111101101000010000000000,
0b011110110100001000000000,
0b001111011010000100000000,
0b000111101101000010000000,
0b101010111001000001000000,
0b111100010011000000100000,
0b110111000110000000010000,
0b011011100011000000001000,
0b100100111110000000000100,
0b010010011111000000000010,
0b110001110101000000000001,
];
const PAR_ALT: &[u32] = &[
0b100000000000110001110101,
0b010000000000011000111011,
0b001000000000111101101000,
0b000100000000011110110100,
0b000010000000001111011010,
0b000001000000110110011001,
0b000000100000011011001101,
0b000000010000001101100111,
0b000000001000110111000110,
0b000000000100101010010111,
0b000000000010100100111110,
0b000000000001100011101011,
];
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_encode() {
assert_eq!(encode(0), 0);
assert_eq!(encode(0b111111111111), 0b111111111111_111111111111);
assert_eq!(encode(0b111111000000), 0b111111000000_110011010001);
assert_eq!(encode(0b000000111111), 0b000000111111_001100101110);
assert_eq!(encode(0b100000000001), 0b100000000001_010010011110);
}
#[test]
fn test_decode() {
let w = 0b111111101010;
let e = encode(w);
assert_eq!(e, 0b111111101010_111011100100);
assert_eq!(decode(e^0b100000000000000000000010), Some((w, 2)));
assert_eq!(decode(e^0b010000000000000000000001), Some((w, 2)));
assert_eq!(decode(e^0b001000000000000000000010), Some((w, 2)));
assert_eq!(decode(e^0b000100000000000000000100), Some((w, 2)));
assert_eq!(decode(e^0b000010000000000000001000), Some((w, 2)));
assert_eq!(decode(e^0b000001000000000000010000), Some((w, 2)));
assert_eq!(decode(e^0b000000100000000000100000), Some((w, 2)));
assert_eq!(decode(e^0b000000010000000001000000), Some((w, 2)));
assert_eq!(decode(e^0b000000001000000010000000), Some((w, 2)));
assert_eq!(decode(e^0b000000000100000100000000), Some((w, 2)));
assert_eq!(decode(e^0b000000000010001000000000), Some((w, 2)));
assert_eq!(decode(e^0b000000000001010000000000), Some((w, 2)));
assert_eq!(decode(e^0b000000000010000000000001), Some((w, 2)));
assert_eq!(decode(e^0b000000000100000000000010), Some((w, 2)));
assert_eq!(decode(e^0b000000001000000000000100), Some((w, 2)));
assert_eq!(decode(e^0b000000010000000000001000), Some((w, 2)));
assert_eq!(decode(e^0b000000100000000000010000), Some((w, 2)));
assert_eq!(decode(e^0b000001000000000000100000), Some((w, 2)));
assert_eq!(decode(e^0b000010000000000001000000), Some((w, 2)));
assert_eq!(decode(e^0b000100000000000010000000), Some((w, 2)));
assert_eq!(decode(e^0b001000000000000100000000), Some((w, 2)));
assert_eq!(decode(e^0b010000000000001000000000), Some((w, 2)));
assert_eq!(decode(e^0b010000000000010000000000), Some((w, 2)));
assert_eq!(decode(e^0b111000000000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b011100000000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b001110000000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b000111000000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b000011100000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b000001110000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b000000111000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b000000011100000000000000), Some((w, 3)));
assert_eq!(decode(e^0b000000001110000000000000), Some((w, 3)));
assert_eq!(decode(e^0b000000000111000000000000), Some((w, 3)));
assert_eq!(decode(e^0b000000000011100000000000), Some((w, 3)));
assert_eq!(decode(e^0b000000000001110000000000), Some((w, 3)));
assert_eq!(decode(e^0b000000000000111000000000), Some((w, 3)));
assert_eq!(decode(e^0b000000000000011100000000), Some((w, 3)));
assert_eq!(decode(e^0b000000000000001110000000), Some((w, 3)));
assert_eq!(decode(e^0b000000000000000111000000), Some((w, 3)));
assert_eq!(decode(e^0b000000000000000011100000), Some((w, 3)));
assert_eq!(decode(e^0b000000000000000001110000), Some((w, 3)));
assert_eq!(decode(e^0b000000000000000000111000), Some((w, 3)));
assert_eq!(decode(e^0b000000000000000000011100), Some((w, 3)));
assert_eq!(decode(e^0b000000000000000000001110), Some((w, 3)));
assert_eq!(decode(e^0b000000000000000000000111), Some((w, 3)));
assert_eq!(decode(e^0b000000000000000000000000), Some((w, 0)));
assert_eq!(decode(e^0b000000000000000000000001), Some((w, 1)));
assert_eq!(decode(e^0b000000000000000000000011), Some((w, 2)));
assert_eq!(decode(e^0b000000000000000000000111), Some((w, 3)));
assert_eq!(decode(e^0b000000001000000000000000), Some((w, 1)));
assert_eq!(decode(e^0b000000011000000000000000), Some((w, 2)));
assert_eq!(decode(e^0b000000111000000000000000), Some((w, 3)));
assert_eq!(decode(e^0b000000100000000000000001), Some((w, 2)));
assert_eq!(decode(e^0b000000110000000000000001), Some((w, 3)));
assert_eq!(decode(e^0b000000100000000000000011), Some((w, 3)));
for w in 0..1<<12 {
assert_eq!(decode(encode(w)), Some((w, 0)));
}
let w = encode(0b110110100110);
for ((i, j), k) in (0..24).zip(0..24).zip(0..24) {
let e: u32 = 1 << i | 1 << j | 1 << k;
let n = e.count_ones() as usize;
assert_eq!(decode(w ^ e), Some((0b110110100110, n)));
}
for (((h, i), j), k) in (0..24).zip(0..24).zip(0..24).zip(0..24) {
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);
}
}
}
}