pub const EXP: [u8; 512] = gen_exp();
pub const LOG: [u8; 256] = gen_log();
pub const INV: [u8; 256] = gen_inv();
const POLY: u32 = 0x11B; const GEN: u8 = 0x03;
const fn gf_mul_slow(mut a: u8, mut b: u8) -> u8 {
let mut result: u8 = 0;
let mut i = 0usize;
while i < 8 {
if b & 1 != 0 {
result ^= a;
}
let hi = a & 0x80;
a <<= 1;
if hi != 0 {
a ^= (POLY & 0xFF) as u8; }
b >>= 1;
i += 1;
}
result
}
const fn gen_exp() -> [u8; 512] {
let mut table = [0u8; 512];
let mut x: u8 = 1;
let mut i = 0usize;
while i < 255 {
table[i] = x;
table[i + 255] = x;
x = gf_mul_slow(x, GEN);
i += 1;
}
table[255] = 1; table[510] = 1;
table[511] = GEN; table
}
const fn gen_log() -> [u8; 256] {
let exp = gen_exp();
let mut table = [0u8; 256];
let mut i = 0usize;
while i < 255 {
table[exp[i] as usize] = i as u8;
i += 1;
}
table
}
const fn gen_inv() -> [u8; 256] {
let log = gen_log();
let exp = gen_exp();
let mut table = [0u8; 256];
let mut i = 1usize;
while i < 256 {
let l = log[i] as usize;
table[i] = exp[255 - l];
i += 1;
}
table
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generator_has_order_255() {
assert_eq!(EXP[255], 1, "g^255 should be 1");
}
#[test]
fn exp_log_round_trip() {
for x in 1u8..=255 {
let l = LOG[x as usize] as usize;
assert_eq!(EXP[l], x, "EXP[LOG[{x}]] != {x}");
}
}
#[test]
fn inv_correctness() {
for x in 1u8..=255 {
let inv_x = INV[x as usize];
let product = gf_mul_slow(x, inv_x);
assert_eq!(product, 1, "x={x} * inv={inv_x} = {product}, expected 1");
}
}
#[test]
fn inv_zero_is_zero() {
assert_eq!(INV[0], 0);
}
#[test]
fn mul_commutativity() {
for a in 0u8..=255 {
for b in 0u8..=7 {
assert_eq!(gf_mul_slow(a, b), gf_mul_slow(b, a));
}
}
}
}