use alloc::{vec, vec::Vec};
static EXP: [u8; 510] = build_exp();
static LOG: [u8; 256] = build_log();
const fn build_exp() -> [u8; 510] {
let mut table = [0; 510];
let mut value: u16 = 1;
let mut index = 0;
while index < 255 {
table[index] = value as u8;
table[index + 255] = value as u8;
value <<= 1;
if value & 0x100 != 0 {
value ^= 0x11D;
}
index += 1;
}
table
}
const fn build_log() -> [u8; 256] {
let mut table = [0; 256];
let mut value: u16 = 1;
let mut index = 0;
while index < 255 {
table[value as usize] = index as u8;
value <<= 1;
if value & 0x100 != 0 {
value ^= 0x11D;
}
index += 1;
}
table
}
pub(crate) fn divisor(degree: usize) -> Vec<u8> {
debug_assert!((1..=255).contains(°ree));
let mut result = vec![0; degree];
result[degree - 1] = 1;
let mut root = 1;
for _ in 0..degree {
for index in 0..degree {
result[index] = multiply(result[index], root);
if index + 1 < degree {
result[index] ^= result[index + 1];
}
}
root = multiply(root, 2);
}
debug_assert!(result.iter().all(|&coefficient| coefficient != 0));
result
}
pub(crate) fn remainder(data: &[u8], divisor: &[u8]) -> Vec<u8> {
let mut result = vec![0; divisor.len()];
for &byte in data {
let factor = byte ^ result[0];
result.copy_within(1.., 0);
*result.last_mut().expect("the divisor is not empty") = 0;
if factor != 0 {
let factor_log = usize::from(LOG[usize::from(factor)]);
for (value, &coefficient) in result.iter_mut().zip(divisor) {
*value ^= EXP[usize::from(LOG[usize::from(coefficient)]) + factor_log];
}
}
}
result
}
#[inline]
fn multiply(x: u8, y: u8) -> u8 {
if x == 0 || y == 0 {
0
} else {
EXP[usize::from(LOG[usize::from(x)]) + usize::from(LOG[usize::from(y)])]
}
}