pub const GF_PRIMITIVE_POLY: u16 = 0x11D;
#[derive(Clone)]
pub struct GaloisField {
exp_table: [u8; 512],
log_table: [u8; 256],
}
impl Default for GaloisField {
fn default() -> Self {
Self::new()
}
}
impl GaloisField {
pub fn new() -> Self {
let mut exp_table = [0u8; 512];
let mut log_table = [0u8; 256];
let mut x = 1u16;
for (i, exp) in exp_table.iter_mut().take(255).enumerate() {
*exp = x as u8;
log_table[x as usize] = i as u8;
x <<= 1;
if x & 0x100 != 0 {
x ^= GF_PRIMITIVE_POLY;
}
}
for i in 255..512 {
exp_table[i] = exp_table[i - 255];
}
Self {
exp_table,
log_table,
}
}
#[inline]
pub fn mul(&self, a: u8, b: u8) -> u8 {
if a == 0 || b == 0 {
return 0;
}
let log_sum = self.log_table[a as usize] as usize + self.log_table[b as usize] as usize;
self.exp_table[log_sum]
}
#[inline]
pub fn div(&self, a: u8, b: u8) -> u8 {
if a == 0 {
return 0;
}
if b == 0 {
panic!("Division by zero in GF(2^8)");
}
let log_diff =
255 + self.log_table[a as usize] as usize - self.log_table[b as usize] as usize;
self.exp_table[log_diff]
}
#[inline]
pub fn pow(&self, a: u8, n: usize) -> u8 {
if a == 0 {
return 0;
}
let log_prod = (self.log_table[a as usize] as usize * n) % 255;
self.exp_table[log_prod]
}
#[inline]
pub fn inv(&self, a: u8) -> u8 {
if a == 0 {
panic!("Zero has no inverse in GF(2^8)");
}
self.exp_table[255 - self.log_table[a as usize] as usize]
}
#[inline]
pub fn add(&self, a: u8, b: u8) -> u8 {
a ^ b
}
#[inline]
pub fn sub(&self, a: u8, b: u8) -> u8 {
a ^ b
}
}
pub struct GfAlgo;
impl GfAlgo {
#[inline]
pub fn multiply(a: u8, b: u8) -> u8 {
let mut p: u16 = 0;
let mut a_copy = a as u16;
let mut b_copy = b as u16;
for _ in 0..8 {
if (a_copy & 1) != 0 {
p ^= b_copy;
}
a_copy >>= 1;
let carry = (b_copy & 0x80) != 0;
b_copy <<= 1;
if carry {
b_copy ^= 0x11D; }
}
p as u8
}
#[inline]
pub unsafe fn xor_vectors(dest: &mut [u8], src: &[u8]) {
let len = core::cmp::min(dest.len(), src.len());
if len == 0 {
return;
}
let dest_ptr = dest.as_mut_ptr();
let src_ptr = src.as_ptr();
let mut i = 0;
unsafe {
while i + 8 <= len {
let d = (dest_ptr.add(i) as *mut u64).read_unaligned();
let s = (src_ptr.add(i) as *const u64).read_unaligned();
(dest_ptr.add(i) as *mut u64).write_unaligned(d ^ s);
i += 8;
}
while i < len {
*dest_ptr.add(i) ^= *src_ptr.add(i);
i += 1;
}
}
}
#[inline]
pub unsafe fn mul_xor_vectors(dest: &mut [u8], src: &[u8], c: u8) {
if c == 0 {
return;
}
let len = core::cmp::min(dest.len(), src.len());
if len == 0 {
return;
}
if c == 1 {
unsafe {
Self::xor_vectors(dest, src);
}
return;
}
unsafe {
let dest_ptr = dest.as_mut_ptr();
let src_ptr = src.as_ptr();
for i in 0..len {
*dest_ptr.add(i) ^= Self::multiply(*src_ptr.add(i), c);
}
}
}
#[inline]
pub fn xor_vectors_safe(dest: &mut [u8], src: &[u8]) {
let len = core::cmp::min(dest.len(), src.len());
for i in 0..len {
dest[i] ^= src[i];
}
}
#[inline]
pub fn mul_xor_vectors_safe(dest: &mut [u8], src: &[u8], c: u8) {
if c == 0 {
return;
}
if c == 1 {
Self::xor_vectors_safe(dest, src);
return;
}
let len = core::cmp::min(dest.len(), src.len());
for i in 0..len {
dest[i] ^= Self::multiply(src[i], c);
}
}
}