use subtle::{Choice, ConditionallySelectable};
fn rm_encode_byte(m: u8) -> [u64; 2] {
const STRIPES_LO: [u64; 7] = [
0xAAAA_AAAA_AAAA_AAAA,
0xCCCC_CCCC_CCCC_CCCC,
0xF0F0_F0F0_F0F0_F0F0,
0xFF00_FF00_FF00_FF00,
0xFFFF_0000_FFFF_0000,
0xFFFF_FFFF_0000_0000,
0x0000_0000_0000_0000,
];
const STRIPES_HI: [u64; 7] = [
0xAAAA_AAAA_AAAA_AAAA,
0xCCCC_CCCC_CCCC_CCCC,
0xF0F0_F0F0_F0F0_F0F0,
0xFF00_FF00_FF00_FF00,
0xFFFF_0000_FFFF_0000,
0xFFFF_FFFF_0000_0000,
0xFFFF_FFFF_FFFF_FFFF,
];
let init: u64 = if (m >> 7) & 1 == 1 { u64::MAX } else { 0 };
let mut lo = init;
let mut hi = init;
for k in 0..7 {
if (m >> k) & 1 == 1 {
lo ^= STRIPES_LO[k];
hi ^= STRIPES_HI[k];
}
}
[lo, hi]
}
pub fn rm_encode(m: u8, multiplicity: usize, out: &mut [u8], bit_offset: usize) {
let [lo, hi] = rm_encode_byte(m);
for rep in 0..multiplicity {
let base_bit = bit_offset + rep * 128;
let base_byte = base_bit / 8;
debug_assert!(base_bit % 8 == 0, "rm_encode requires byte-aligned output");
let lo_bytes = lo.to_le_bytes();
out[base_byte..base_byte + 8].copy_from_slice(&lo_bytes);
let hi_bytes = hi.to_le_bytes();
out[base_byte + 8..base_byte + 16].copy_from_slice(&hi_bytes);
}
}
fn wht(f: &mut [i16; 128]) {
let mut step = 1usize;
while step < 128 {
let mut i = 0;
while i < 128 {
for j in i..i + step {
let a = f[j];
let b = f[j + step];
f[j] = a + b;
f[j + step] = a - b;
}
i += 2 * step;
}
step <<= 1;
}
}
pub fn rm_decode(block: &[u8], multiplicity: usize) -> u8 {
debug_assert_eq!(block.len(), 16 * multiplicity);
let mut f = [0i16; 128];
for rep in 0..multiplicity {
let base = rep * 16; for i in 0..128 {
let byte_idx = i / 8;
let bit_idx = i % 8;
let bit = (block[base + byte_idx] >> bit_idx) & 1;
f[i] += 1 - 2 * (bit as i16);
}
}
wht(&mut f);
let mut best_abs = 0i16;
let mut best_idx = 0u8;
let mut best_neg = 0u8;
for k in 0..128usize {
let val = f[k];
let abs_val = val.abs();
let is_neg = (val < 0) as u8;
let update = Choice::from((abs_val > best_abs) as u8);
best_abs = i16::conditional_select(&best_abs, &abs_val, update);
best_idx = u8::conditional_select(&best_idx, &(k as u8), update);
best_neg = u8::conditional_select(&best_neg, &is_neg, update);
}
(best_neg << 7) | (best_idx & 0x7F)
}
#[cfg(test)]
mod tests {
use super::*;
fn encode_byte_to_vec(m: u8, multiplicity: usize) -> Vec<u8> {
let len = 16 * multiplicity; let mut buf = vec![0u8; len];
rm_encode(m, multiplicity, &mut buf, 0);
buf
}
#[test]
fn encode_zero_gives_all_zeros() {
for mult in [3, 5] {
let buf = encode_byte_to_vec(0, mult);
assert!(buf.iter().all(|&b| b == 0), "mult={mult}");
}
}
#[test]
fn encode_255_gives_all_ones() {
let buf = encode_byte_to_vec(0xFF, 3);
assert_eq!(buf.len(), 48);
assert_eq!(&buf[0..16], &buf[16..32]);
assert_eq!(&buf[0..16], &buf[32..48]);
}
#[test]
fn encode_duplicates_are_identical() {
for m in [0u8, 1, 42, 128, 255] {
for mult in [3usize, 5] {
let buf = encode_byte_to_vec(m, mult);
for rep in 1..mult {
assert_eq!(&buf[0..16], &buf[rep * 16..rep * 16 + 16],
"m={m} mult={mult} rep={rep}");
}
}
}
}
#[test]
fn codeword_weight_is_correct() {
for m in 0u8..=255 {
let [lo, hi] = rm_encode_byte(m);
let weight = lo.count_ones() + hi.count_ones();
let expected = match m {
0 => 0,
128 => 128,
_ => 64,
};
assert_eq!(weight, expected, "m={m:#04x}");
}
}
#[test]
fn decode_roundtrip_no_errors_mult3() {
for m in 0u8..=255 {
let buf = encode_byte_to_vec(m, 3);
let decoded = rm_decode(&buf, 3);
assert_eq!(decoded, m, "m={m}");
}
}
#[test]
fn decode_roundtrip_no_errors_mult5() {
for m in 0u8..=255 {
let buf = encode_byte_to_vec(m, 5);
let decoded = rm_decode(&buf, 5);
assert_eq!(decoded, m, "m={m}");
}
}
fn flip_bit(buf: &mut [u8], pos: usize) {
buf[pos / 8] ^= 1 << (pos % 8);
}
#[test]
fn decode_corrects_up_to_capacity_mult3() {
let m = 0xABu8;
let mut buf = encode_byte_to_vec(m, 3);
for i in 0..95 {
flip_bit(&mut buf, i);
}
let decoded = rm_decode(&buf, 3);
assert_eq!(decoded, m, "failed with 95 errors");
}
#[test]
fn decode_corrects_up_to_capacity_mult5() {
let m = 0xCDu8;
let mut buf = encode_byte_to_vec(m, 5);
for i in 0..159 {
flip_bit(&mut buf, i);
}
let decoded = rm_decode(&buf, 5);
assert_eq!(decoded, m, "failed with 159 errors");
}
#[test]
fn decode_single_bit_error_each_position_mult3() {
let m = 0x55u8;
let clean = encode_byte_to_vec(m, 3);
for pos in 0..384 {
let mut buf = clean.clone();
flip_bit(&mut buf, pos);
let decoded = rm_decode(&buf, 3);
assert_eq!(decoded, m, "single bit flip at pos={pos}");
}
}
#[test]
fn wht_of_unit_vector_is_all_ones_row() {
let mut f = [0i16; 128];
f[0] = 1;
wht(&mut f);
assert!(f.iter().all(|&v| v == 1));
}
#[test]
fn wht_involution() {
let mut f = [0i16; 128];
for i in 0..128 {
f[i] = (i as i16 % 7) - 3; }
let original = f;
wht(&mut f);
wht(&mut f);
for i in 0..128 {
assert_eq!(f[i], 128 * original[i], "index {i}");
}
}
}