use std::ops::{Add, Mul, Sub};
#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
#[inline]
fn gf256_multiply_const_time(a: u8, b: u8) -> u8 {
let mut a = a;
let mut b = b;
let mut p: u8 = 0;
for _ in 0..8 {
if (b & 1) != 0 {
p ^= a;
}
let carry = a & 0x80;
a <<= 1;
if carry != 0 {
a ^= 0x1b; }
b >>= 1;
}
p
}
#[inline]
fn gf256_inverse_const_time(a: u8) -> u8 {
if a == 0 {
return 0;
}
let mut result = 1u8;
let mut base = a;
let mut exp = 254u32;
while exp > 0 {
if exp & 1 == 1 {
result = gf256_multiply_const_time(result, base);
}
base = gf256_multiply_const_time(base, base);
exp >>= 1;
}
result
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "zeroize", derive(Zeroize))]
pub struct FiniteField(pub u8);
impl FiniteField {
#[inline]
pub fn new(value: u8) -> Self {
Self(value)
}
#[inline]
pub fn multiply(self, other: Self) -> Self {
Self(gf256_multiply_const_time(self.0, other.0))
}
#[inline]
pub fn exp(self, mut exp: u32) -> Self {
let mut result = FiniteField::new(1);
let mut base = self;
while exp > 0 {
if exp & 1 == 1 {
result = result.multiply(base);
}
base = base.multiply(base);
exp >>= 1;
}
result
}
#[inline]
pub fn inverse(self) -> Option<Self> {
if self.0 == 0 {
None
} else {
Some(Self(gf256_inverse_const_time(self.0)))
}
}
}
impl Add for FiniteField {
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
#[allow(clippy::suspicious_arithmetic_impl)]
let result = self.0 ^ other.0;
Self(result)
}
}
impl Mul for FiniteField {
type Output = Self;
#[inline]
fn mul(self, other: Self) -> Self {
self.multiply(other)
}
}
impl Sub for FiniteField {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
#[allow(clippy::suspicious_arithmetic_impl)]
let result = self.add(other);
result
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_addition() {
let a = FiniteField::new(0x53);
let b = FiniteField::new(0xCA);
assert_eq!((a + b).0, 0x99);
}
#[test]
fn test_multiplication() {
let a = FiniteField::new(0x53);
let b = FiniteField::new(0xCA);
assert_eq!((a * b).0, 0x1);
}
#[test]
fn test_inverse() {
let a = FiniteField::new(0x53);
let inv = a.inverse().unwrap();
assert_eq!((a * inv).0, 0x01);
}
#[test]
fn test_zero_inverse() {
let zero = FiniteField::new(0);
assert_eq!(zero.inverse(), None);
}
#[test]
fn test_multiplication_associativity() {
let a = FiniteField::new(0x53);
let b = FiniteField::new(0xCA);
let c = FiniteField::new(0x7B);
assert_eq!((a * b) * c, a * (b * c));
}
#[test]
fn test_all_inverses() {
for i in 1..=255 {
let a = FiniteField::new(i);
let inv = a.inverse().unwrap();
assert_eq!((a * inv).0, 0x01);
}
}
#[test]
fn test_specific_inverses() {
let test_values = [(0x53, 0xCA), (0x7B, 0x06), (0xA4, 0x8F), (0xE1, 0x0D)];
for &(a, expected_inv) in &test_values {
let field_a = FiniteField::new(a);
let inv = field_a.inverse().unwrap();
assert_eq!(inv.0, expected_inv, "Inverse mismatch for 0x{:02X}", a);
assert_eq!((field_a * inv).0, 0x01);
}
}
#[test]
fn test_commutativity() {
let a = FiniteField::new(0x53);
let b = FiniteField::new(0xCA);
assert_eq!(a * b, b * a);
}
#[test]
fn test_distributivity() {
let a = FiniteField::new(0x12);
let b = FiniteField::new(0x34);
let c = FiniteField::new(0x56);
assert_eq!(a * (b + c), (a * b) + (a * c));
}
#[test]
fn test_identity() {
let one = FiniteField::new(1);
let value = FiniteField::new(0xAB);
assert_eq!(value * one, value);
}
}