pub struct GF256 {
mul_table: [[u8; 256]; 256],
inv_table: [u8; 256],
pub alpha: u8,
pub primitive_polynomial: u8,
}
impl GF256 {
fn gf_multiply(a: u8, b: u8, primitive_polynomial: u8) -> u8 {
let mut result = 0u8;
let mut a = a;
let mut b = b;
while b != 0 {
if b & 1 != 0 {
result ^= a;
}
let carry = a & 0x80;
a <<= 1;
if carry != 0 {
a ^= primitive_polynomial;
}
b >>= 1;
}
result
}
pub fn new(primitive_polynomial: u16) -> Self {
let mut mul_table = [[0u8; 256]; 256];
let mut inv_table = [0u8; 256];
for (i, row) in mul_table.iter_mut().enumerate() {
for (j, cell) in row.iter_mut().enumerate() {
*cell = Self::gf_multiply(i as u8, j as u8, primitive_polynomial as u8);
}
}
for i in 1..256 {
for j in 1..256 {
if mul_table[i][j] == 1 {
inv_table[i] = j as u8;
break;
}
}
}
Self {
mul_table,
inv_table,
alpha: 0x02_u8,
primitive_polynomial: primitive_polynomial as u8,
}
}
#[inline]
pub fn add(&self, a: u8, b: u8) -> u8 {
a ^ b
}
#[inline]
pub fn mul_lookup(&self, a: u8, b: u8) -> u8 {
self.mul_table[a as usize][b as usize]
}
pub fn multiply(&self, a: u8, b: u8) -> u8 {
match a {
0 => 0,
1 => b,
_ => self.mul_table[a as usize][b as usize],
}
}
#[inline]
pub fn mul_alpha(&self, a: u8) -> u8 {
if a == 0 {
return 0;
}
if a == 1 {
return self.alpha;
}
if a < 128 {
return a << 1;
}
self.add(a << 1, self.primitive_polynomial)
}
#[inline]
pub fn inverse(&self, a: u8) -> u8 {
if a == 0 {
panic!("Inverse of zero does not exist in finite field");
}
self.inv_table[a as usize]
}
#[inline]
pub fn divide(&self, a: u8, b: u8) -> u8 {
if b == 0 {
panic!("Division by zero in finite field");
}
self.multiply(a, self.inverse(b))
}
pub fn vector_addition_inplace(&self, result: &mut [u8], vec: &[u8]) {
for (i, &vec_elem) in vec.iter().enumerate() {
result[i] = self.add(result[i], vec_elem);
}
}
pub fn multiply_alpha_inplace(&self, result: &mut [u8]) {
for elem in result.iter_mut() {
*elem = self.mul_alpha(*elem);
}
}
pub fn scalar_vector_multiply_inplace(&self, scalar: u8, result: &mut [u8]) {
for elem in result.iter_mut() {
*elem = self.multiply(scalar, *elem);
}
}
}
impl Default for GF256 {
fn default() -> Self {
Self::new(0x11B)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gf256_basic_operations() {
let field = GF256::default();
assert_eq!(field.add(5, 3), 6);
assert_eq!(field.add(0, 7), 7);
assert_eq!(field.add(7, 7), 0);
assert_eq!(field.multiply(0, 5), 0);
assert_eq!(field.multiply(5, 0), 0);
assert_eq!(field.multiply(1, 5), 5);
assert_eq!(field.multiply(5, 1), 5);
assert_eq!(field.multiply(5, field.inverse(5)), 1);
assert_eq!(field.multiply(7, field.inverse(7)), 1);
}
#[test]
#[should_panic(expected = "Inverse of zero")]
fn test_inverse_of_zero() {
let field = GF256::default();
field.inverse(0);
}
#[test]
fn test_gf256_multiplication_table() {
let field = GF256::default();
assert_eq!(field.multiply(2, 0), 0);
assert_eq!(field.multiply(2, 3), 6);
assert_eq!(field.multiply(7, 11), 49); assert_eq!(field.multiply(255, 1), 255);
assert_eq!(field.multiply(255, 255), 19); }
#[test]
fn test_gf256_inverse_table() {
let field = GF256::default();
for i in 1u8..=255u8 {
let inv = field.inverse(i);
assert_eq!(field.multiply(i, inv), 1);
}
}
#[test]
fn test_gf256_distributive_law() {
let field = GF256::default();
let a = 5;
let b = 3;
let c = 7;
let left = field.multiply(a, field.add(b, c));
let right = field.add(field.multiply(a, b), field.multiply(a, c));
assert_eq!(left, right);
}
#[test]
fn test_gf256_associative_law() {
let field = GF256::default();
let a = 5;
let b = 3;
let c = 7;
let left = field.multiply(field.multiply(a, b), c);
let right = field.multiply(a, field.multiply(b, c));
assert_eq!(left, right);
}
#[test]
fn test_gf256_commutative_law() {
let field = GF256::default();
let a = 5;
let b = 3;
assert_eq!(field.multiply(a, b), field.multiply(b, a));
}
#[test]
fn test_gf256_zero_and_identity() {
let field = GF256::default();
for i in 0u8..=255u8 {
assert_eq!(field.add(0, i), i);
assert_eq!(field.add(i, 0), i);
assert_eq!(field.multiply(0, i), 0);
assert_eq!(field.multiply(i, 0), 0);
}
for i in 0u8..=255u8 {
assert_eq!(field.multiply(1, i), i);
assert_eq!(field.multiply(i, 1), i);
}
}
#[test]
fn test_gf256_division_consistency() {
let field = GF256::default();
for i in 1u8..=255u8 {
for j in 1u8..=255u8 {
let product = field.multiply(i, j);
let quotient = field.multiply(product, field.inverse(i));
assert_eq!(quotient, j);
}
}
}
#[test]
fn test_mul_alpha_consistency() {
let field = GF256::default();
for x in 0u8..=255u8 {
let result_mul_alpha = field.mul_alpha(x);
let result_multiply = field.multiply(x, field.alpha);
assert_eq!(
result_mul_alpha, result_multiply,
"mul_alpha({}) = {} but multiply({}, alpha) = {}",
x, result_mul_alpha, x, result_multiply
);
}
}
}