use std::{array, env, fs::File, path::Path};
const BITS: usize = 8;
const ORDER: usize = 256;
const MODULUS: u8 = 255;
const POLYNOMIAL: usize = 0x11D;
const CANTOR_BASIS: [u8; BITS] = [1, 214, 152, 146, 86, 200, 88, 230];
macro_rules! write_table {
($dest:expr, $table:ident) => {{
let typ = type_name_of_val(&$table);
let name = stringify!($table).to_ascii_uppercase();
let table = format!("pub static {name}: {typ} = {:?};\n", $table);
::std::io::Write::write_all($dest, table.as_bytes()).expect(&format!(
"Failed to write lookup table: {}",
stringify!($table)
));
}};
}
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("table.rs");
let mut outfile = File::create(dest_path).expect("Failed to create file for lookup tables");
let (log, exp) = create_log_tables();
write_table!(&mut outfile, log);
write_table!(&mut outfile, exp);
let mul = create_mul_table(&log, &exp);
write_table!(&mut outfile, mul);
}
fn create_log_tables() -> ([u8; ORDER], [u8; ORDER]) {
let mut log_table = [0u8; ORDER];
let mut exp_table = [0u8; ORDER];
let mut state: usize = 1;
for i in 0..MODULUS {
exp_table[state] = i;
state <<= 1;
if state >= ORDER {
state ^= POLYNOMIAL;
}
}
exp_table[0] = MODULUS;
log_table[0] = 0;
for (i, basis) in CANTOR_BASIS.iter().enumerate() {
let width = 1 << i;
for j in 0..width {
log_table[j + width] = log_table[j] ^ basis;
}
}
log_table = array::from_fn(|i| exp_table[log_table[i] as usize]);
for i in 0..ORDER {
exp_table[log_table[i] as usize] = i.try_into().expect("must be valid u8");
}
exp_table[MODULUS as usize] = exp_table[0];
(log_table, exp_table)
}
fn create_mul_table(log_table: &[u8; ORDER], exp_table: &[u8; ORDER]) -> [[u8; ORDER]; ORDER] {
let mut mul8_table = [[0u8; ORDER]; ORDER];
for lut in mul8_table.iter_mut() {
lut[0] = 0;
}
for (x, &log_x) in log_table.iter().enumerate().skip(1) {
for log_y in 0..=MODULUS {
let exp = add_mod(log_x, log_y) as usize;
mul8_table[log_y as usize][x] = exp_table[exp];
}
}
mul8_table
}
const fn add_mod(a: u8, b: u8) -> u8 {
let sum = a as u32 + b as u32;
(sum + (sum >> BITS)) as u8
}
fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
std::any::type_name::<T>()
}