#[inline]
pub(super) fn gf_mul(mut a: u8, mut b: u8) -> u8 {
let mut product = 0u8;
let mut i = 0;
while i < 8 {
let bit = 0u8.wrapping_sub(b & 1); product ^= bit & a;
let carry = 0u8.wrapping_sub(a >> 7); a = (a << 1) ^ (carry & 0x1b);
b >>= 1;
i += 1;
}
product
}
#[inline]
pub(super) fn gf_inv(x: u8) -> u8 {
let x2 = gf_mul(x, x); let x4 = gf_mul(x2, x2); let x8 = gf_mul(x4, x4); let x16 = gf_mul(x8, x8); let x32 = gf_mul(x16, x16); let x64 = gf_mul(x32, x32); let x128 = gf_mul(x64, x64);
let mut r = x2;
r = gf_mul(r, x4);
r = gf_mul(r, x8);
r = gf_mul(r, x16);
r = gf_mul(r, x32);
r = gf_mul(r, x64);
gf_mul(r, x128)
}
#[inline]
pub(super) fn sub_byte(x: u8) -> u8 {
let inv = gf_inv(x);
inv ^ inv.rotate_left(1) ^ inv.rotate_left(2) ^ inv.rotate_left(3) ^ inv.rotate_left(4) ^ 0x63
}
#[inline]
pub(super) fn inv_sub_byte(x: u8) -> u8 {
let t = x.rotate_left(1) ^ x.rotate_left(3) ^ x.rotate_left(6) ^ 0x05;
gf_inv(t)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gf_mul_known() {
assert_eq!(gf_mul(0x57, 0x13), 0xfe);
assert_eq!(gf_mul(0x57, 0x83), 0xc1);
assert_eq!(gf_mul(0x00, 0xff), 0x00);
assert_eq!(gf_mul(0x01, 0xab), 0xab); }
#[test]
fn gf_inv_is_inverse() {
assert_eq!(gf_inv(0), 0);
for x in 1u16..=255 {
let x = x as u8;
assert_eq!(gf_mul(x, gf_inv(x)), 1, "inverse failed for {x:#04x}");
}
}
#[test]
fn sbox_known_values() {
assert_eq!(sub_byte(0x00), 0x63);
assert_eq!(sub_byte(0x01), 0x7c);
assert_eq!(sub_byte(0x10), 0xca);
assert_eq!(sub_byte(0x53), 0xed);
assert_eq!(sub_byte(0x7c), 0x10);
assert_eq!(sub_byte(0xff), 0x16);
}
#[test]
fn sbox_is_bijection_and_invertible() {
let mut seen = [false; 256];
for x in 0u16..=255 {
let x = x as u8;
let s = sub_byte(x);
assert!(!seen[s as usize], "S-box not injective at {x:#04x}");
seen[s as usize] = true;
assert_eq!(inv_sub_byte(s), x, "inv S-box failed for {x:#04x}");
}
}
}