pub(super) const SM4_GF_POLY: u8 = 0xF5;
const A_FIRST_ROW: u8 = 0xD3;
pub(super) const AFFINE_B: u8 = 0xD3;
pub(super) const A_ROWS: [u8; 8] = [
A_FIRST_ROW.rotate_right(0),
A_FIRST_ROW.rotate_right(1),
A_FIRST_ROW.rotate_right(2),
A_FIRST_ROW.rotate_right(3),
A_FIRST_ROW.rotate_right(4),
A_FIRST_ROW.rotate_right(5),
A_FIRST_ROW.rotate_right(6),
A_FIRST_ROW.rotate_right(7),
];
#[inline]
const fn gf_mul(mut a: u8, mut b: u8) -> u8 {
let mut r: u8 = 0;
let mut i = 0;
while i < 8 {
let mask = 0u8.wrapping_sub(b & 1);
r ^= a & mask;
let high = 0u8.wrapping_sub((a >> 7) & 1);
a = (a << 1) ^ (SM4_GF_POLY & high);
b >>= 1;
i += 1;
}
r
}
#[inline]
const 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 r1 = gf_mul(x128, x64);
let r2 = gf_mul(r1, x32);
let r3 = gf_mul(r2, x16);
let r4 = gf_mul(r3, x8);
let r5 = gf_mul(r4, x4);
gf_mul(r5, x2)
}
#[inline]
const fn affine_a(x: u8) -> u8 {
let mut out: u8 = 0;
let mut i = 0u32;
while i < 8 {
let row = A_ROWS[i as usize];
let prod = row & x;
let parity = (prod.count_ones() & 1) as u8;
out |= parity << (7 - i);
i += 1;
}
out
}
#[inline]
#[must_use]
pub(super) const fn sbox_byte(x: u8) -> u8 {
let pre = affine_a(x) ^ AFFINE_B;
let inv = gf_inv(pre);
affine_a(inv) ^ AFFINE_B
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scalar_sbox_self_consistent_on_zero_one() {
assert_eq!(sbox_byte(0x00), 0xD6);
assert_eq!(sbox_byte(0x01), 0x90);
}
}