1const MODULUS: u8 = 0x1b;
19
20#[inline(always)]
22pub const fn mul(mut a: u8, mut b: u8) -> u8 {
23 let mut p: u8 = 0;
24 let mut i = 0;
25 while i < 8 {
26 p ^= a & (b & 1).wrapping_neg();
28 let hi = (a >> 7) & 1;
30 a <<= 1;
31 a ^= MODULUS & hi.wrapping_neg();
32 b >>= 1;
33 i += 1;
34 }
35 p
36}
37
38#[inline(always)]
40pub const fn xtime(a: u8) -> u8 {
41 let hi = (a >> 7) & 1;
42 (a << 1) ^ (MODULUS & hi.wrapping_neg())
43}
44
45#[inline(always)]
50pub const fn inv(x: u8) -> u8 {
51 let mut r = x;
52 let mut bit = 6i32;
53 while bit >= 0 {
55 r = mul(r, r);
56 if bit > 0 {
57 r = mul(r, x);
58 }
59 bit -= 1;
60 }
61 r
62}
63
64#[inline(always)]
66pub const fn sbox(x: u8) -> u8 {
67 let y = inv(x);
68 y ^ y.rotate_left(1) ^ y.rotate_left(2) ^ y.rotate_left(3) ^ y.rotate_left(4) ^ 0x63
69}
70
71#[inline(always)]
73pub const fn inv_sbox(y: u8) -> u8 {
74 let t = y.rotate_left(1) ^ y.rotate_left(3) ^ y.rotate_left(6) ^ 0x05;
75 inv(t)
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 const SBOX_REFERENCE: [u8; 256] = [
85 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab,
86 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4,
87 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71,
88 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
89 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6,
90 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb,
91 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45,
92 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
93 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44,
94 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a,
95 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49,
96 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
97 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25,
98 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e,
99 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1,
100 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
101 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb,
102 0x16,
103 ];
104
105 #[test]
106 fn algebraic_sbox_matches_fips197() {
107 for x in 0..=255u8 {
108 assert_eq!(sbox(x), SBOX_REFERENCE[x as usize], "S({x:#04x})");
109 }
110 }
111
112 #[test]
113 fn inverse_sbox_undoes_sbox() {
114 for x in 0..=255u8 {
115 assert_eq!(inv_sbox(sbox(x)), x, "S^-1(S({x:#04x}))");
116 }
117 }
118
119 #[test]
120 fn field_inversion_is_correct() {
121 assert_eq!(inv(0), 0);
122 for x in 1..=255u8 {
123 assert_eq!(mul(x, inv(x)), 1, "x * x^-1 for {x:#04x}");
124 }
125 }
126
127 #[test]
128 fn xtime_matches_multiplication_by_two() {
129 for x in 0..=255u8 {
130 assert_eq!(xtime(x), mul(x, 2));
131 }
132 }
133}