refactor: align platform crate boundaries

This commit is contained in:
bfloat16
2026-09-07 19:29:54 +08:00
parent aa1bcaa2eb
commit 6250ca4e98
43 changed files with 1004 additions and 1004 deletions
+161
View File
@@ -0,0 +1,161 @@
//! AES inverse tables (inverse S-box + InvMixColumns "Td" T-tables), generated
//! at compile time from GF(2^8) arithmetic rather than embedded as a transcribed
//! blob. These are the standard AES *decryption* tables — not proprietary data —
//! so we derive them. The generated bytes are verified byte-identical to the
//! original hand-transcribed arrays (CRC32-locked in the test at the bottom).
//!
//! Each table is 1024 bytes = 256 u32 little-endian, read by
//! `primitives::aes_round` via `get_u32(&TABLE, x * 4)`. The byte layout matches
//! the original exactly, so `aes_round` is unchanged:
//! SBOX[x] = invsbox(x) broadcast to 4 bytes
//! COLUMMIX1[x] = [0b*s, 0d*s, 09*s, 0e*s], s = invsbox(x) (Td0, this byte order)
//! COLUMMIX2/3/4 = COLUMMIX1's 4-byte group rotated left by 1 / 2 / 3 bytes
//!
//! Generated the same way as the existing `const fn` CRC-table generation in
//! `crc32.rs`.
/// GF(2^8) multiply with the AES reduction polynomial (x^8 + x^4 + x^3 + x + 1).
const fn gf_mul(mut a: u8, mut b: u8) -> u8 {
let mut p: u8 = 0;
let mut i = 0;
while i < 8 {
if b & 1 != 0 {
p ^= a;
}
let hi = a & 0x80;
a <<= 1;
if hi != 0 {
a ^= 0x1B;
}
b >>= 1;
i += 1;
}
p
}
/// The AES inverse S-box, derived from the multiplicative inverse in GF(2^8)
/// followed by inverting the forward S-box's affine transform.
const fn inv_sbox() -> [u8; 256] {
// Multiplicative inverse: inv[a] = b such that a*b == 1 (inv[0] stays 0).
let mut inv = [0u8; 256];
let mut a = 1usize;
while a < 256 {
let mut b = 1usize;
while b < 256 {
if gf_mul(a as u8, b as u8) == 1 {
inv[a] = b as u8;
break;
}
b += 1;
}
a += 1;
}
// Forward S-box: affine transform over the inverse.
let mut sb = [0u8; 256];
let mut i = 0usize;
while i < 256 {
let mut x = inv[i];
let mut s = inv[i];
let mut r = 0;
while r < 4 {
s = s.rotate_left(1);
x ^= s;
r += 1;
}
sb[i] = x ^ 0x63;
i += 1;
}
// Inverse S-box is the inverse permutation of the forward S-box.
let mut isb = [0u8; 256];
let mut i = 0usize;
while i < 256 {
isb[sb[i] as usize] = i as u8;
i += 1;
}
isb
}
/// The five generated tables (each 1024 bytes = 256 u32 LE).
struct AesTables {
cm1: [u8; 1024],
cm2: [u8; 1024],
cm3: [u8; 1024],
cm4: [u8; 1024],
sbox: [u8; 1024],
}
/// Build all five tables in one compile-time pass.
const fn build_tables() -> AesTables {
let isb = inv_sbox();
let mut cm1 = [0u8; 1024];
let mut cm2 = [0u8; 1024];
let mut cm3 = [0u8; 1024];
let mut cm4 = [0u8; 1024];
let mut sbox = [0u8; 1024];
let mut x = 0usize;
while x < 256 {
let s = isb[x];
// SBOX: invsbox(x) broadcast to all four lanes.
let mut j = 0;
while j < 4 {
sbox[x * 4 + j] = s;
j += 1;
}
// COLUMMIX1 lane bytes; CM2/3/4 are byte-rotations of the same four.
let b = [
gf_mul(0x0b, s),
gf_mul(0x0d, s),
gf_mul(0x09, s),
gf_mul(0x0e, s),
];
let mut j = 0;
while j < 4 {
cm1[x * 4 + j] = b[j];
cm2[x * 4 + j] = b[(j + 1) % 4];
cm3[x * 4 + j] = b[(j + 2) % 4];
cm4[x * 4 + j] = b[(j + 3) % 4];
j += 1;
}
x += 1;
}
AesTables {
cm1,
cm2,
cm3,
cm4,
sbox,
}
}
const TABLES: AesTables = build_tables();
pub static COLUMMIX1: [u8; 1024] = TABLES.cm1;
pub static COLUMMIX2: [u8; 1024] = TABLES.cm2;
pub static COLUMMIX3: [u8; 1024] = TABLES.cm3;
pub static COLUMMIX4: [u8; 1024] = TABLES.cm4;
pub static SBOX: [u8; 1024] = TABLES.sbox;
#[cfg(test)]
mod tests {
use super::*;
/// Lock the generated tables to the original hand-transcribed bytes. The
/// CRC32 oracles were computed from the previously-committed `tables.rs`
/// arrays; any drift in the generator (or the GF math) fails here before it
/// can reach the byte-identical corpus goldens.
#[test]
fn generated_tables_match_committed_bytes() {
assert_eq!(COLUMMIX1.len(), 1024);
assert_eq!(crate::crc32::compute(&COLUMMIX1), 0x7e8d_5d5f);
assert_eq!(crate::crc32::compute(&COLUMMIX2), 0xfcc4_acfc);
assert_eq!(crate::crc32::compute(&COLUMMIX3), 0x637a_f0cd);
assert_eq!(crate::crc32::compute(&COLUMMIX4), 0x1e7b_c381);
assert_eq!(crate::crc32::compute(&SBOX), 0x10fd_6dc1);
// Spot-check the first dword of each (matches the original first row).
assert_eq!(&COLUMMIX1[..4], &[0x50, 0xa7, 0xf4, 0x51]);
assert_eq!(&COLUMMIX2[..4], &[0xa7, 0xf4, 0x51, 0x50]);
assert_eq!(&COLUMMIX3[..4], &[0xf4, 0x51, 0x50, 0xa7]);
assert_eq!(&COLUMMIX4[..4], &[0x51, 0x50, 0xa7, 0xf4]);
assert_eq!(&SBOX[..4], &[0x52, 0x52, 0x52, 0x52]);
}
}