#![no_std]
#![deny(missing_docs)]
use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug, Hash)]
pub struct GF(pub u8);
impl GF {
pub fn multiplicative_inverse(self) -> Self {
let mut p = 0;
for x in 0u8..=255u8 {
let y = (self * GF(x)).0 ^ 1;
let or = y | y >> 1 | y >> 2 | y >> 3 | y >> 4 | y >> 5 | y >> 6 | y >> 7;
p ^= !extend_bit(or) & x;
}
GF(p)
}
}
#[inline(always)]
fn extend_bit(input: u8) -> u8 {
(((input) as i8) << 7).wrapping_shr(7) as u8
}
impl From<u8> for GF {
fn from(x: u8) -> Self {
GF(x)
}
}
impl Add for GF {
type Output = Self;
#[inline(always)]
fn add(self, rhs: Self) -> Self::Output {
#[allow(clippy::suspicious_arithmetic_impl)]
Self(self.0 ^ rhs.0)
}
}
impl AddAssign for GF {
#[inline(always)]
fn add_assign(&mut self, rhs: Self) {
*self = self.add(rhs)
}
}
impl Sub for GF {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
self.add(rhs)
}
}
impl SubAssign for GF {
fn sub_assign(&mut self, rhs: Self) {
self.add_assign(rhs)
}
}
impl Mul for GF {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
let mut a = self.0;
let mut b = rhs.0;
let mut p = 0;
for _ in 0..8 {
p ^= extend_bit(b & 1) & a;
b >>= 1;
let carry = (a >> 7) & 1;
a <<= 1;
a ^= extend_bit(carry & 1) & 0x1b;
}
GF(p)
}
}
impl MulAssign for GF {
fn mul_assign(&mut self, rhs: Self) {
*self = self.mul(rhs)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_multiplicative_inverse() {
assert_eq!(GF(0x01).multiplicative_inverse(), GF(0x01));
assert_eq!(GF(0x02).multiplicative_inverse(), GF(0x8d));
assert_eq!(GF(0x03).multiplicative_inverse(), GF(0xf6));
assert_eq!(GF(0x04).multiplicative_inverse(), GF(0xcb));
assert_eq!(GF(0x05).multiplicative_inverse(), GF(0x52));
assert_eq!(GF(0x06).multiplicative_inverse(), GF(0x7b));
assert_eq!(GF(0xff).multiplicative_inverse(), GF(0x1c));
}
#[test]
fn test_shift_behaviour() {
let mut x: i8 = 1;
x <<= 7;
assert_eq!(x as u8, 0b1000_0000 as u8);
x = x.wrapping_shr(7);
assert_eq!(x as u8, 0b1111_1111);
let mut x: i8 = 0;
x <<= 7;
assert_eq!(x as u8, 0b0000_0000 as u8);
x = x.wrapping_shr(7);
assert_eq!(x as u8, 0b0000_0000 as u8);
}
#[test]
fn test_extend_bit() {
assert_eq!(extend_bit(1), 0xff);
assert_eq!(extend_bit(0), 0x00);
assert_eq!(extend_bit(0b0000_0001), 0xff);
assert_eq!(extend_bit(0b0000_0000), 0x00);
assert_eq!(extend_bit(0b1000_0100), 0x00);
assert_eq!(extend_bit(0b0100_0100), 0x00);
assert_eq!(extend_bit(0b1100_0101), 0xff);
}
#[test]
fn multiplication_example_wikipedia() {
let mut x = GF(0x53);
x *= GF(0xCA);
assert_eq!(x, GF(0x01))
}
#[test]
fn multiplication_example_fips197_4_2() {
let mut x = GF(0x57);
x *= GF(0x83);
assert_eq!(x, GF(0xc1))
}
#[test]
fn multiplication_example_fips197_4_2_1() {
assert_eq!(GF(0x57) * GF(0x01), GF(0x57));
assert_eq!(GF(0x57) * GF(0x02), GF(0xae));
assert_eq!(GF(0x57) * GF(0x04), GF(0x47));
assert_eq!(GF(0x57) * GF(0x08), GF(0x8e));
assert_eq!(GF(0x57) * GF(0x10), GF(0x07));
let mut x = GF(0x57);
x *= GF(0x13);
assert_eq!(x, GF(0xfe))
}
#[test]
fn zero_addition() {
assert_eq!(GF(0x53) + GF(0x0), GF(0x53));
}
#[test]
fn zero_subtraction() {
assert_eq!(GF(0x53) - GF(0x0), GF(0x53));
}
#[test]
fn simple_addition_assign() {
let mut x = GF(0x22);
x += GF(0x81);
assert_eq!(x, GF(0xa3))
}
#[test]
fn simple_subtraction_assign() {
let mut x = GF(0x93);
x -= GF(0x5b);
assert_eq!(x, GF(0xc8))
}
}