Skip to main content

ferritls_core/
aes.rs

1//! AES 块密码(FIPS 197),128/192/256 位密钥的软件实现。
2//!
3//! FIPS 批准;作为 GCM/CCM 与 CTR-DRBG 的底层部件,上电自检覆盖(M5)。
4//! AES-NI 后端在 M8+ 经 [`crate::ops`] 入口挂接,不影响本模块公开 API。
5//!
6//! 常数时间策略:S-box 不查表——**批量路径(P1 起)为位切片纯布尔
7//! 电路**(逆元 = GF(2^8) 多项式基下 x^254 加法链 + FIPS-197 仿射
8//! 变换,平方 = 平面重排 + 折叠),零查表、零秘密相关分支/访存;
9//! **单块路径为 16 宽掩码全扫描**(`sub_bytes`:一次表遍历同时
10//! 服务全部 16 字节,访问模式与输入无关)。实测单块走位切片电路
11//! 反而慢约 2×(电路平面操作数按"批"固定,单块仅占极小 lane 占比),
12//! 故两路径并存。字节移位/列混合全部为算术与掩码操作。轮密钥与
13//! 其位平面 Drop 时零化。
14//!
15//! P2(`simd` feature,默认启用):位切片电路按平面元素 `Plane`
16//! 泛型——`u64`(64 块/批,P1 标量形态原样保留)与
17//! `Simd<u64, L>`(64·L 块/批)共享同一份电路源码;
18//! `encrypt_ctr_batch` 按公开请求块数在 64/128/256/512 块档位中
19//! 取最小浪费档,向量宽度随编译目标自动决定(SSE2 每平面元素 2×
20//! u64 / AVX2 4× / AVX-512 8×)。显式向量类型保证宽 ISA 下的通道
21//! 利用率不依赖 LLVM 自动向量化启发式(P2 基线实测:P1 代码在
22//! +avx2/+avx512 下吞吐几乎不变)。
23//!
24//! 向量:FIPS-197 附录 C.1/C.2/C.3 KAT(`tests` 内嵌)+ GCM 集成 KAT;
25//! 位切片电路与 16 宽扫描分别对照逐字节标量实现(`bitslice_*`、
26//! `sub_bytes_matches_scalar` 测试);批量各档位对照逐块标量
27//! (`encrypt_ctr_batch_matches_scalar`)。
28
29/// 官方 S-box(FIPS-197 图 7)。
30const SBOX: [u8; 256] = [
31    0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
32    0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
33    0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
34    0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
35    0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
36    0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
37    0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
38    0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
39    0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
40    0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
41    0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
42    0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
43    0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
44    0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
45    0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
46    0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
47];
48
49/// 逆 S-box:由正表程序化求逆(S-box 为双射,结果唯一)。
50const INV_SBOX: [u8; 256] = {
51    let mut inv = [0u8; 256];
52    let mut x = 0usize;
53    while x < 256 {
54        let mut i = 0usize;
55        loop {
56            if SBOX[i] as usize == x {
57                inv[x] = i as u8;
58                break;
59            }
60            i += 1;
61        }
62        x += 1;
63    }
64    inv
65};
66
67/// GF(2^8) 倍乘(xtime)。
68fn xtime(x: u8) -> u8 {
69    let hi = ((x >> 7) & 1).wrapping_neg();
70    (x << 1) ^ (hi & 0x1b)
71}
72
73/// GF(2^8) 分支无关乘法。
74fn gf_mul(mut a: u8, mut b: u8) -> u8 {
75    let mut p = 0u8;
76    for _ in 0..8 {
77        p ^= a & ((b & 1).wrapping_neg());
78        let hi = ((a >> 7) & 1).wrapping_neg();
79        a = (a << 1) ^ (hi & 0x1b);
80        b >>= 1;
81    }
82    p
83}
84
85/// 常数时间表访问:遍历全部 256 项,按相等掩码选择。
86/// 访问模式与输入无关(无缓存侧信道)。
87#[inline]
88fn ct_table_lookup(table: &[u8; 256], x: u8) -> u8 {
89    let mut acc = 0u8;
90    for (i, &entry) in table.iter().enumerate() {
91        let eq = (((i as u8) ^ x) == 0) as u8;
92        acc |= entry & eq.wrapping_neg();
93    }
94    acc
95}
96
97#[inline]
98fn sbox(x: u8) -> u8 {
99    ct_table_lookup(&SBOX, x)
100}
101
102#[inline]
103/// 逐字节逆 S-box(生产路径已改用 [`inv_sub_bytes`],保留为等价
104/// 测试的独立 oracle)。
105#[cfg(test)]
106fn inv_sbox(x: u8) -> u8 {
107    ct_table_lookup(&INV_SBOX, x)
108}
109
110/// SubBytes(P1 余留优化):一次 256 项扫描同时服务全部 16 字节。
111/// 内层对固定表项的 16 字节"相等→掩码→选择"是连续定长形状,LLVM
112/// 将其向量化为宽 SIMD(每表项约 4-5 条向量指令);逐字节各跑一遍
113/// [`sbox`] 扫描则无法融合,实测慢约 3 倍。访问模式与输入无关
114///(全表遍历),ct 性质与 [`ct_table_lookup`] 相同。
115#[inline]
116fn sub_bytes(s: &mut [u8; 16]) {
117    let mut acc = [0u8; 16];
118    for (i, &entry) in SBOX.iter().enumerate() {
119        let idx = i as u8;
120        for (a, &x) in acc.iter_mut().zip(s.iter()) {
121            let eq = ((x == idx) as u8).wrapping_neg();
122            *a |= entry & eq;
123        }
124    }
125    *s = acc;
126}
127
128/// InvSubBytes:[`sub_bytes`] 的逆表版本(解密方向,无生产调用方,
129/// 保持与加密方向同构)。
130#[inline]
131fn inv_sub_bytes(s: &mut [u8; 16]) {
132    let mut acc = [0u8; 16];
133    for (i, &entry) in INV_SBOX.iter().enumerate() {
134        let idx = i as u8;
135        for (a, &x) in acc.iter_mut().zip(s.iter()) {
136            let eq = ((x == idx) as u8).wrapping_neg();
137            *a |= entry & eq;
138        }
139    }
140    *s = acc;
141}
142
143fn sub_word(w: [u8; 4]) -> [u8; 4] {
144    [sbox(w[0]), sbox(w[1]), sbox(w[2]), sbox(w[3])]
145}
146
147macro_rules! aes_impl {
148    ($name:ident, $nk:expr, $nr:expr, $doc:expr) => {
149        #[doc = $doc]
150        #[derive(Clone)]
151        pub struct $name {
152            /// 轮密钥(Nr+1 × 16 字节,按 FIPS-197 列序展开)。
153            rk: Vec<u8>,
154            /// 轮密钥位平面(broadcast 形态):`rk_planes[r][g][b]` = 轮 r
155            /// 字节 g 的比特 b 广播到全部 64 lane。位切片路径(单块与
156            /// 批量)直接 XOR,免去每次调用的平面展开。秘密材料,
157            /// Drop 零化。
158            rk_planes: Vec<[Planes; 16]>,
159        }
160
161        impl $name {
162            /// 密钥字节数。
163            pub const KEY_LEN: usize = $nk * 4;
164            const NR: usize = $nr;
165
166            /// 展开密钥。
167            pub fn new(key: &[u8; $nk * 4]) -> Self {
168                let total = 16 * ($nr + 1);
169                let mut rk = vec![0u8; total];
170                let nk_bytes = $nk * 4;
171                rk[..nk_bytes].copy_from_slice(key);
172
173                let mut rcon = 1u8;
174                let mut i = nk_bytes;
175                while i < total {
176                    let mut t: [u8; 4] = rk[i - 4..i].try_into().unwrap();
177                    if i % nk_bytes == 0 {
178                        t = sub_word([t[1], t[2], t[3], t[0]]);
179                        t[0] ^= rcon;
180                        rcon = xtime(rcon);
181                    } else if $nk > 6 && i % nk_bytes == 16 {
182                        t = sub_word(t);
183                    }
184                    for j in 0..4 {
185                        rk[i + j] = rk[i - nk_bytes + j] ^ t[j];
186                    }
187                    i += 4;
188                }
189                let mut rk_planes = Vec::with_capacity($nr + 1);
190                for round in 0..=$nr {
191                    let mut planes = [[0u64; 8]; 16];
192                    for g in 0..16 {
193                        for (b, plane) in planes[g].iter_mut().enumerate() {
194                            *plane = u64::from((rk[round * 16 + g] >> b) & 1).wrapping_neg();
195                        }
196                    }
197                    rk_planes.push(planes);
198                }
199                Self { rk, rk_planes }
200            }
201
202            fn add_round_key(&self, state: &mut [u8; 16], round: usize) {
203                for j in 0..16 {
204                    state[j] ^= self.rk[round * 16 + j];
205                }
206            }
207
208            /// 就地加密一个块(掩码全扫描,P1 余留优化:SubBytes 以
209            /// `sub_bytes` 单次扫描同时服务全部 16 字节——累加器内层
210            /// 16 字节比较/选择被 LLVM 向量化为宽 SIMD,实测约为逐字节
211            /// 扫描的 3 倍。位切片电路的平面操作数按"批"固定,单块仅
212            /// 占 1/64 lane,实测反而慢 2×,故单块保持掩码路径。
213            pub fn encrypt_block(&self, block: &mut [u8; 16]) {
214                let mut s = *block;
215                self.add_round_key(&mut s, 0);
216                for round in 1..Self::NR {
217                    sub_bytes(&mut s);
218                    shift_rows(&mut s);
219                    mix_columns(&mut s);
220                    self.add_round_key(&mut s, round);
221                }
222                sub_bytes(&mut s);
223                shift_rows(&mut s);
224                self.add_round_key(&mut s, Self::NR);
225                *block = s;
226            }
227
228            /// 就地解密一个块(等价逆变换;DRBG 与 GCM 只需加密方向)。
229            pub fn decrypt_block(&self, block: &mut [u8; 16]) {
230                let mut s = *block;
231                self.add_round_key(&mut s, Self::NR);
232                for round in (1..Self::NR).rev() {
233                    inv_shift_rows(&mut s);
234                    inv_sub_bytes(&mut s);
235                    self.add_round_key(&mut s, round);
236                    inv_mix_columns(&mut s);
237                }
238                inv_shift_rows(&mut s);
239                inv_sub_bytes(&mut s);
240                self.add_round_key(&mut s, 0);
241                *block = s;
242            }
243
244            /// 批量加密计数器块(位切片路径,P1;P2 档位分发):以
245            /// `base` 为第 0 块,加密"base 低 32 位 + i"(i = 0..n)共
246            /// n(≤ [`CTR_BATCH_BLOCKS`])个块,每块 16 字节密钥流写入
247            /// `out`。未用 lane 计算任意值但不写出。装载利用 CTR 结构:
248            /// 前 12 字节跨块常量(平面全 0/全 1),仅低 32 位计数器按
249            /// lane 展开。档位按公开 n 取最小浪费:64(u64,P1 形态)/
250            /// 128/256/512(Simd<u64,2/4/8>,仅 simd feature)。
251            /// 供 GCM/CCM/DRBG 的 CTR 密钥流使用;仅加密方向。
252            ///(Aes192 当前无批量调用方——GCM/CCM/DRBG 用 128/256——
253            /// 随宏同型生成,保留完整实例 API。)
254            #[allow(dead_code)]
255            pub(crate) fn encrypt_ctr_batch(&self, base: [u8; 16], n: usize, out: &mut [u8]) {
256                debug_assert!(n > 0 && n <= CTR_BATCH_BLOCKS && out.len() >= n * 16);
257                #[cfg(feature = "simd")]
258                {
259                    if n <= 64 {
260                        encrypt_ctr_batch_p::<u64>(&self.rk_planes, base, n, out)
261                    } else if n <= 128 {
262                        encrypt_ctr_batch_p::<Simd<u64, 2>>(&self.rk_planes, base, n, out)
263                    } else if n <= 256 {
264                        encrypt_ctr_batch_p::<Simd<u64, 4>>(&self.rk_planes, base, n, out)
265                    } else {
266                        encrypt_ctr_batch_p::<Simd<u64, 8>>(&self.rk_planes, base, n, out)
267                    }
268                }
269                #[cfg(not(feature = "simd"))]
270                encrypt_ctr_batch_p::<u64>(&self.rk_planes, base, n, out);
271            }
272        }
273
274        impl Drop for $name {
275            fn drop(&mut self) {
276                self.rk.fill(0);
277                self.rk_planes.fill([[0u64; 8]; 16]);
278            }
279        }
280
281        impl std::fmt::Debug for $name {
282            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
283                f.write_str(stringify!($name))
284            }
285        }
286    };
287}
288
289// ---------------------------------------------------------------------------
290// 位切片批量加密路径(P1 性能轮;P2 平面元素泛型化)
291//
292// 表示:state = 16 个字节组 × 8 个位平面。平面元素 P 实现位运算且
293// 承载一批块在同一字节位置同一比特上的值:u64 的 bit i(lane i)承载
294// 第 i 块 → 一批 64 块;`Simd<u64, L>`(simd feature)的每个元素是一个
295// 64-lane 组 → 一批 64·L 块。布尔运算逐元素即逐块并行,电路源码对
296// P 泛型(u64 实例 = P1 标量形态,逐位对照穷举验证)。零查表、零秘密
297// 相关控制流。
298//
299// 电路代数(全部与上方标量实现穷举对照验证):
300// - GF(2^8) 乘法:多项式基卷积(64 AND)+ 折叠约减
301//   (x^8=x^4+x^3+x+1 及其倍数);
302// - 平方:偶次幂平面重排 + x^8/x^10/x^12/x^14 折叠,无乘法;
303// - 逆元 x^254 = x^192·x^48·x^14(4 次乘法 + 9 次平方的加法链);
304// - 仿射:s_i = b_i ⊕ b_{i+4} ⊕ b_{i+5} ⊕ b_{i+6} ⊕ b_{i+7} ⊕ c_i
305//   (下标 mod 8,c = 0x63;c_i=1 时平面取反)。
306// ---------------------------------------------------------------------------
307
308use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
309
310#[cfg(feature = "simd")]
311use std::simd::Simd;
312
313/// 位平面元素(P2):一批块在同一字节位置同一比特上的并行承载。
314///
315/// `u64` = 64 块/批(P1 标量形态);`Simd<u64, L>` = 64·L 块/批,
316/// 每个 Simd 元素是一个独立的 64-lane 组(装载/提取按组进行,
317/// 见 [`encrypt_ctr_batch_p`])。所有方法 `#[inline]`:u64 实例的
318/// broadcast/组装配均为恒等操作,电路代码生成与 P1 逐位一致。
319trait Plane:
320    Copy
321    + BitAnd<Output = Self>
322    + BitOr<Output = Self>
323    + BitXor<Output = Self>
324    + Not<Output = Self>
325    + BitAndAssign
326    + BitOrAssign
327    + BitXorAssign
328{
329    /// 一批覆盖的块数。
330    const LANES: usize;
331    /// 同一 u64 值用于全部 lane 组(常数平面 / 轮密钥平面广播,
332    /// 入参恒为 0 或 !0)。
333    fn broadcast(x: u64) -> Self;
334    /// 由"每个 64-lane 组的平面值"装配(计数器装载用)。
335    fn from_lane_groups(f: impl FnMut(usize) -> u64) -> Self;
336    /// 取第 e 个 64-lane 组的平面值(e < `LANES / 64`;提取用)。
337    fn to_lane_group(self, e: usize) -> u64;
338}
339
340impl Plane for u64 {
341    const LANES: usize = 64;
342    #[inline]
343    fn broadcast(x: u64) -> Self {
344        x
345    }
346    #[inline]
347    fn from_lane_groups(mut f: impl FnMut(usize) -> u64) -> Self {
348        f(0)
349    }
350    #[inline]
351    fn to_lane_group(self, e: usize) -> u64 {
352        debug_assert_eq!(e, 0);
353        self
354    }
355}
356
357// 本 rustc 的 portable_simd 中 `Simd<T, N>` 仅要求 `T: SimdElement`,
358// N 为任意 const 泛型参数(无需 LaneCount bound)。
359#[cfg(feature = "simd")]
360impl<const L: usize> Plane for Simd<u64, L> {
361    const LANES: usize = 64 * L;
362    #[inline]
363    fn broadcast(x: u64) -> Self {
364        Simd::splat(x)
365    }
366    #[inline]
367    fn from_lane_groups(f: impl FnMut(usize) -> u64) -> Self {
368        Simd::from_array(core::array::from_fn(f))
369    }
370    #[inline]
371    fn to_lane_group(self, e: usize) -> u64 {
372        self.to_array()[e]
373    }
374}
375
376/// 64 位位平面组:一个状态字节在 64 个块上的全部比特。
377type Planes = [u64; 8];
378
379/// 一批并行加密的最大块数(= 最大档位平面覆盖)。
380/// simd feature:512 块(Simd<u64,8> 每平面 8×64 lane);
381/// 标量回退:64 块(P1 形态)。
382#[cfg(feature = "simd")]
383pub(crate) const CTR_BATCH_BLOCKS: usize = 512;
384#[cfg(not(feature = "simd"))]
385pub(crate) const CTR_BATCH_BLOCKS: usize = 64;
386
387/// GF(2^8) 位切片乘法:卷积 t_k = Σ_{i+j=k} a_i·b_j 后折叠约减。
388/// 折叠关系(f = x^8+x^4+x^3+x+1):
389/// x^8→{4,3,1,0},x^9→{5,4,2,1},x^10→{6,5,3,2},x^11→{7,6,4,3},
390/// x^12→{7,5,3,1,0},x^13→{6,3,2,0},x^14→{7,4,3,1}。
391fn bs_mul<P: Plane>(a: &[P; 8], b: &[P; 8]) -> [P; 8] {
392    let mut t = [P::broadcast(0); 15];
393    for i in 0..8 {
394        for j in 0..8 {
395            t[i + j] ^= a[i] & b[j];
396        }
397    }
398    [
399        t[0] ^ t[8] ^ t[12] ^ t[13],
400        t[1] ^ t[8] ^ t[9] ^ t[12] ^ t[14],
401        t[2] ^ t[9] ^ t[10] ^ t[13],
402        t[3] ^ t[8] ^ t[10] ^ t[11] ^ t[12] ^ t[13] ^ t[14],
403        t[4] ^ t[8] ^ t[9] ^ t[11] ^ t[14],
404        t[5] ^ t[9] ^ t[10] ^ t[12],
405        t[6] ^ t[10] ^ t[11] ^ t[13],
406        t[7] ^ t[11] ^ t[12] ^ t[14],
407    ]
408}
409
410/// GF(2^8) 位切片平方:a_i → 偶次幂平面 2i,折叠 x^8/x^10/x^12/x^14
411///(奇次卷积项为 0,折叠集见 [`bs_mul`])。
412fn bs_sq<P: Plane>(a: &[P; 8]) -> [P; 8] {
413    [
414        a[0] ^ a[4] ^ a[6],
415        a[4] ^ a[6] ^ a[7],
416        a[1] ^ a[5],
417        a[4] ^ a[5] ^ a[6] ^ a[7],
418        a[2] ^ a[4] ^ a[7],
419        a[5] ^ a[6],
420        a[3] ^ a[5],
421        a[6] ^ a[7],
422    ]
423}
424
425/// GF(2^8) 位切片乘 x(xtime):a_i → i+1,a_7 折叠 0x1b。
426fn bs_xtime<P: Plane>(a: &[P; 8]) -> [P; 8] {
427    [
428        a[7],
429        a[0] ^ a[7],
430        a[1],
431        a[2] ^ a[7],
432        a[3] ^ a[7],
433        a[4],
434        a[5],
435        a[6],
436    ]
437}
438
439/// 位切片 S-box:就地把一个字节组替换为 S-box 输出。
440fn bs_sbox<P: Plane>(x: &mut [P; 8]) {
441    let a = *x;
442    // 逆元 x^254:
443    let x2 = bs_sq(&a);
444    let x3 = bs_mul(&a, &x2); // x^3
445    let x6 = bs_sq(&x3);
446    let x12 = bs_sq(&x6);
447    let x24 = bs_sq(&x12);
448    let x48 = bs_sq(&x24);
449    let x96 = bs_sq(&x48);
450    let x192 = bs_sq(&x96);
451    let x4 = bs_sq(&x2);
452    let x7 = bs_mul(&x3, &x4); // x^7
453    let x14 = bs_sq(&x7);
454    let t = bs_mul(&x192, &x48);
455    let inv = bs_mul(&t, &x14); // x^(192+48+14) = x^254
456    // 仿射变换(FIPS-197 §5.1.1)。
457    for i in 0..8 {
458        let mut s =
459            inv[i] ^ inv[(i + 4) % 8] ^ inv[(i + 5) % 8] ^ inv[(i + 6) % 8] ^ inv[(i + 7) % 8];
460        if (0x63 >> i) & 1 == 1 {
461            s = !s; // XOR 常数 1 平面 = 取反
462        }
463        x[i] = s;
464    }
465}
466
467/// 位切片轮函数(批量路径):`st` 已含 ARK(0),完成 1..Nr-1
468/// 轮(S-box/Shift/Mix/ARK)与终轮(S-box/Shift/ARK)。
469/// `rk_planes` 长度 = Nr+1;Simd 档位下轮密钥平面 splat-on-use,
470/// 不新增秘密存储。
471fn bs_rounds<P: Plane>(st: &mut [[P; 8]; 16], rk_planes: &[[Planes; 16]]) {
472    for rk in &rk_planes[1..rk_planes.len() - 1] {
473        for group in st.iter_mut() {
474            bs_sbox(group);
475        }
476        bs_shift_rows(st);
477        bs_mix_columns(st);
478        for (sg, rg) in st.iter_mut().zip(rk.iter()) {
479            for (s, r) in sg.iter_mut().zip(rg.iter()) {
480                *s ^= P::broadcast(*r);
481            }
482        }
483    }
484    for group in st.iter_mut() {
485        bs_sbox(group);
486    }
487    bs_shift_rows(st);
488    let rk = &rk_planes[rk_planes.len() - 1];
489    for (sg, rg) in st.iter_mut().zip(rk.iter()) {
490        for (s, r) in sg.iter_mut().zip(rg.iter()) {
491            *s ^= P::broadcast(*r);
492        }
493    }
494}
495
496/// 位切片 ShiftRows:字节组层面的平面重排(flat = 4*col + row)。
497fn bs_shift_rows<P: Plane>(s: &mut [[P; 8]; 16]) {
498    let t = *s;
499    for row in 1..4 {
500        for col in 0..4 {
501            s[4 * col + row] = t[4 * ((col + row) % 4) + row];
502        }
503    }
504}
505
506/// 位切片 MixColumns:out = M·in,M 同标量路径(xtime 组合)。
507fn bs_mix_columns<P: Plane>(s: &mut [[P; 8]; 16]) {
508    for c in 0..4 {
509        let o = 4 * c;
510        let (a0, a1, a2, a3) = (s[o], s[o + 1], s[o + 2], s[o + 3]);
511        let xt0 = bs_xtime(&a0);
512        let xt1 = bs_xtime(&a1);
513        let xt2 = bs_xtime(&a2);
514        let xt3 = bs_xtime(&a3);
515        for b in 0..8 {
516            s[o][b] = xt0[b] ^ xt1[b] ^ a1[b] ^ a2[b] ^ a3[b];
517            s[o + 1][b] = a0[b] ^ xt1[b] ^ xt2[b] ^ a2[b] ^ a3[b];
518            s[o + 2][b] = a0[b] ^ a1[b] ^ xt2[b] ^ xt3[b] ^ a3[b];
519            s[o + 3][b] = xt0[b] ^ a0[b] ^ a1[b] ^ a2[b] ^ xt3[b];
520        }
521    }
522}
523
524/// 计数器字节的某一个 64-lane 组的位平面(大端低 32 位 + lane)。
525/// 与块数/计数器一样属公开量。
526fn ctr_group_planes(ctr0: u32, e: usize, n: usize) -> [[u64; 8]; 16] {
527    let mut grp = [[0u64; 8]; 16];
528    for i in 0..64usize {
529        let lane = e * 64 + i;
530        if lane < n {
531            let ctr = ctr0.wrapping_add(lane as u32).to_be_bytes();
532            for k in 0..4 {
533                for (b, slot) in grp[12 + k].iter_mut().enumerate() {
534                    *slot |= u64::from((ctr[k] >> b) & 1) << i;
535                }
536            }
537        }
538    }
539    grp
540}
541
542/// 批量加密核心(P2 泛型):以 `base` 为第 0 块,加密"base 低 32
543/// 位加 i"(i = 0..n,n ≤ `P::LANES`)共 n 个块,每块 16 字节密钥流
544/// 写入 `out`。未用 lane 计算任意值但不写出。装载/提取按 64-lane
545/// 组进行后装配为 P;档位选择在
546/// [`encrypt_ctr_batch`](Aes128::encrypt_ctr_batch) 按公开 n 完成,
547/// 本函数零分支于秘密。
548fn encrypt_ctr_batch_p<P: Plane>(
549    rk_planes: &[[Planes; 16]],
550    base: [u8; 16],
551    n: usize,
552    out: &mut [u8],
553) {
554    debug_assert!(n > 0 && n <= P::LANES && out.len() >= n * 16);
555
556    // 装载:前 12 字节跨块常量 → 全 0/全 1 平面。
557    let mut st = [[P::broadcast(0); 8]; 16];
558    for (g, byte) in base[..12].iter().enumerate() {
559        for (b, plane) in st[g].iter_mut().enumerate() {
560            *plane = P::broadcast(u64::from((byte >> b) & 1).wrapping_neg());
561        }
562    }
563    // 计数器低 32 位(大端)按 lane 展开:逐 64-lane 组展开后装配。
564    let ctr0 = u32::from_be_bytes(base[12..16].try_into().unwrap());
565    let ng = P::LANES / 64;
566    let mut groups = [[[0u64; 8]; 16]; 8]; // 上限档位 512 块 = 8 组
567    for (e, slot) in groups.iter_mut().enumerate().take(ng) {
568        *slot = ctr_group_planes(ctr0, e, n);
569    }
570    for g in 12..16 {
571        for (b, slot) in st[g].iter_mut().enumerate() {
572            *slot = P::from_lane_groups(|e| groups[e][g][b]);
573        }
574    }
575
576    // ARK(0) + 主轮。
577    let rk0 = &rk_planes[0];
578    for (sg, rg) in st.iter_mut().zip(rk0.iter()) {
579        for (s, r) in sg.iter_mut().zip(rg.iter()) {
580            *s ^= P::broadcast(*r);
581        }
582    }
583    bs_rounds(&mut st, rk_planes);
584
585    // 提取前 n 个 lane(逐组拉平为 u64 平面后逐 lane 装配字节)。
586    for e in 0..ng {
587        let grp = st.map(|g8| {
588            let mut grp8 = [0u64; 8];
589            for (slot, p) in grp8.iter_mut().zip(g8.iter()) {
590                *slot = p.to_lane_group(e);
591            }
592            grp8
593        });
594        for i in 0..64usize {
595            let lane = e * 64 + i;
596            if lane >= n {
597                continue; // n 公开
598            }
599            for (g, group) in grp.iter().enumerate() {
600                let mut byte = 0u8;
601                for (b, plane) in group.iter().enumerate() {
602                    byte |= (((plane >> i) & 1) as u8) << b;
603                }
604                out[lane * 16 + g] = byte;
605            }
606        }
607    }
608}
609
610fn shift_rows(s: &mut [u8; 16]) {
611    // flat index = 4*col + row(FIPS-197 列序)
612    let t = *s;
613    for row in 1..4 {
614        for col in 0..4 {
615            s[4 * col + row] = t[4 * ((col + row) % 4) + row];
616        }
617    }
618}
619
620fn inv_shift_rows(s: &mut [u8; 16]) {
621    let t = *s;
622    for row in 1..4 {
623        for col in 0..4 {
624            s[4 * ((col + row) % 4) + row] = t[4 * col + row];
625        }
626    }
627}
628
629fn mix_columns(s: &mut [u8; 16]) {
630    for c in 0..4 {
631        let o = 4 * c;
632        let (a0, a1, a2, a3) = (s[o], s[o + 1], s[o + 2], s[o + 3]);
633        // 矩阵 [2 3 1 1; 1 2 3 1; 1 1 2 3; 3 1 1 2]
634        s[o] = xtime(a0) ^ xtime(a1) ^ a1 ^ a2 ^ a3;
635        s[o + 1] = a0 ^ xtime(a1) ^ xtime(a2) ^ a2 ^ a3;
636        s[o + 2] = a0 ^ a1 ^ xtime(a2) ^ xtime(a3) ^ a3;
637        s[o + 3] = xtime(a0) ^ a0 ^ a1 ^ a2 ^ xtime(a3);
638    }
639}
640
641fn inv_mix_columns(s: &mut [u8; 16]) {
642    for c in 0..4 {
643        let o = 4 * c;
644        let (a0, a1, a2, a3) = (s[o], s[o + 1], s[o + 2], s[o + 3]);
645        s[o] = gf_mul(a0, 14) ^ gf_mul(a1, 11) ^ gf_mul(a2, 13) ^ gf_mul(a3, 9);
646        s[o + 1] = gf_mul(a0, 9) ^ gf_mul(a1, 14) ^ gf_mul(a2, 11) ^ gf_mul(a3, 13);
647        s[o + 2] = gf_mul(a0, 13) ^ gf_mul(a1, 9) ^ gf_mul(a2, 14) ^ gf_mul(a3, 11);
648        s[o + 3] = gf_mul(a0, 11) ^ gf_mul(a1, 13) ^ gf_mul(a2, 9) ^ gf_mul(a3, 14);
649    }
650}
651
652aes_impl!(Aes128, 4, 10, "AES-128 块密码实例。");
653aes_impl!(Aes192, 6, 12, "AES-192 块密码实例。");
654aes_impl!(Aes256, 8, 14, "AES-256 块密码实例。");
655
656#[cfg(test)]
657mod tests {
658    use super::*;
659
660    #[test]
661    fn sbox_known_values_and_bijection() {
662        // FIPS-197 官方锚点。
663        assert_eq!(sbox(0x00), 0x63);
664        assert_eq!(sbox(0x01), 0x7c);
665        assert_eq!(sbox(0x53), 0xed);
666        assert_eq!(sbox(0xff), 0x16);
667        // P1:代数 sbox 与官方表逐值一致(穷举)。
668        for (x, &official) in SBOX.iter().enumerate() {
669            assert_eq!(sbox(x as u8), official, "sbox({x:#04x})");
670        }
671        let mut seen = [false; 256];
672        for x in 0..=255u8 {
673            assert_eq!(inv_sbox(sbox(x)), x, "round trip at {x}");
674            seen[sbox(x) as usize] = true;
675        }
676        assert!(seen.iter().all(|&s| s), "sbox must be a bijection");
677    }
678
679    #[test]
680    fn fips197_appendix_c_kats() {
681        // C.1: AES-128
682        let mut key = [0u8; 16];
683        for (i, b) in key.iter_mut().enumerate() {
684            *b = i as u8;
685        }
686        let aes = Aes128::new(&key);
687        let mut block = [
688            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
689            0xee, 0xff,
690        ];
691        aes.encrypt_block(&mut block);
692        assert_eq!(
693            block,
694            [
695                0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4,
696                0xc5, 0x5a
697            ]
698        );
699        aes.decrypt_block(&mut block);
700        assert_eq!(
701            block,
702            [
703                0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
704                0xee, 0xff
705            ]
706        );
707
708        // C.3: AES-256
709        let mut key = [0u8; 32];
710        for (i, b) in key.iter_mut().enumerate() {
711            *b = i as u8;
712        }
713        let aes = Aes256::new(&key);
714        let mut block = [
715            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
716            0xee, 0xff,
717        ];
718        aes.encrypt_block(&mut block);
719        assert_eq!(
720            block,
721            [
722                0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49,
723                0x60, 0x89
724            ]
725        );
726        aes.decrypt_block(&mut block);
727        assert_eq!(
728            block,
729            [
730                0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
731                0xee, 0xff,
732            ]
733        );
734    }
735
736    #[test]
737    fn bitslice_circuits_match_scalar_exhaustive() {
738        // 每个 u8 值广播到全部 64 个 lane:bs_mul/bs_sq/bs_xtime/bs_sbox
739        // 与标量实现逐值一致(bs_sq 与 gf_mul(v,v) 互为 oracle)。
740        let planes_of = |v: u8| -> Planes {
741            let mut p = [0u64; 8];
742            for (b, plane) in p.iter_mut().enumerate() {
743                *plane = u64::from((v >> b) & 1).wrapping_neg();
744            }
745            p
746        };
747        let byte_of = |p: &Planes| -> u8 {
748            let mut v = 0u8;
749            for (b, plane) in p.iter().enumerate() {
750                v |= ((plane & 1) as u8) << b;
751            }
752            v
753        };
754        for v in 0..=255u8 {
755            let a = planes_of(v);
756            assert_eq!(byte_of(&bs_sq(&a)), gf_mul(v, v), "sq({v:#04x})");
757            assert_eq!(byte_of(&bs_xtime(&a)), xtime(v), "xtime({v:#04x})");
758            let mut s = a;
759            bs_sbox(&mut s);
760            assert_eq!(byte_of(&s), sbox(v), "sbox({v:#04x})");
761        }
762        // 双操作数全空间(65536 对)。
763        for x in 0..=255u8 {
764            for y in 0..=255u8 {
765                assert_eq!(
766                    byte_of(&bs_mul(&planes_of(x), &planes_of(y))),
767                    gf_mul(x, y),
768                    "mul({x:#04x},{y:#04x})"
769                );
770            }
771        }
772        // lane 独立性:64 个 lane 各放不同值,逐 lane 校验 S-box。
773        let mut lanes = [0u8; 64];
774        let mut seed = 0x9E37_79B9u32;
775        for v in lanes.iter_mut() {
776            seed ^= seed << 13;
777            seed ^= seed >> 17;
778            seed ^= seed << 5;
779            *v = seed as u8;
780        }
781        let mut group = [0u64; 8];
782        for (lane, &v) in lanes.iter().enumerate() {
783            for (b, plane) in group.iter_mut().enumerate() {
784                *plane |= u64::from((v >> b) & 1) << lane;
785            }
786        }
787        bs_sbox(&mut group);
788        for (lane, &v) in lanes.iter().enumerate() {
789            let mut got = 0u8;
790            for (b, plane) in group.iter().enumerate() {
791                got |= (((plane >> lane) & 1) as u8) << b;
792            }
793            assert_eq!(got, sbox(v), "lane {lane}");
794        }
795    }
796
797    #[test]
798    fn sub_bytes_matches_scalar() {
799        // 16 宽单次扫描 vs 逐字节 ct_table_lookup(独立实现),穷举
800        // 边界 + 随机状态;正/逆表同测(sbox 穷举锚定见
801        // sbox_known_values_and_bijection)。
802        let mut seed = 0x243F_6A88u32;
803        let mut next = || {
804            seed ^= seed << 13;
805            seed ^= seed >> 17;
806            seed ^= seed << 5;
807            seed
808        };
809        let mut states = vec![[0u8; 16], [0xff; 16], [0x53; 16]];
810        for _ in 0..64 {
811            states.push(core::array::from_fn(|_| next() as u8));
812        }
813        for st in &states {
814            let mut fwd = *st;
815            sub_bytes(&mut fwd);
816            let mut inv = *st;
817            inv_sub_bytes(&mut inv);
818            for g in 0..16 {
819                assert_eq!(fwd[g], sbox(st[g]), "sub_bytes state={st:?} g={g}");
820                assert_eq!(inv[g], inv_sbox(st[g]), "inv_sub_bytes state={st:?} g={g}");
821            }
822        }
823    }
824
825    #[test]
826    fn encrypt_ctr_batch_matches_scalar() {
827        let mut key = [0u8; 16];
828        for (i, b) in key.iter_mut().enumerate() {
829            *b = i as u8;
830        }
831        let aes = Aes128::new(&key);
832        let mut key256 = [0u8; 32];
833        for (i, b) in key256.iter_mut().enumerate() {
834            *b = (i * 7) as u8;
835        }
836        let aes256 = Aes256::new(&key256);
837        let mut base = [
838            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0x00, 0x00,
839            0x00, 0x01,
840        ];
841        // 覆盖全部批量档位边界(P2:64/128/256/512 块档按 n 分发)。
842        #[cfg(feature = "simd")]
843        let sizes = [
844            1usize, 2, 3, 63, 64, 65, 100, 128, 129, 200, 256, 257, 300, 511, 512,
845        ];
846        #[cfg(not(feature = "simd"))]
847        let sizes = [1usize, 2, 3, 63, 64];
848        for n in sizes {
849            let mut fast = vec![0u8; CTR_BATCH_BLOCKS * 16];
850            aes.encrypt_ctr_batch(base, n, &mut fast);
851            let mut expect = vec![0u8; n * 16];
852            let ctr0 = u32::from_be_bytes(base[12..16].try_into().unwrap());
853            for i in 0..n {
854                let mut blk = base;
855                blk[12..16].copy_from_slice(&ctr0.wrapping_add(i as u32).to_be_bytes());
856                aes.encrypt_block(&mut blk);
857                expect[i * 16..(i + 1) * 16].copy_from_slice(&blk);
858            }
859            assert_eq!(&fast[..n * 16], &expect, "n={n} aes128");
860            // aes256 单独比对
861            let mut expect256 = vec![0u8; n * 16];
862            for i in 0..n {
863                let mut blk = base;
864                blk[12..16].copy_from_slice(&ctr0.wrapping_add(i as u32).to_be_bytes());
865                aes256.encrypt_block(&mut blk);
866                expect256[i * 16..(i + 1) * 16].copy_from_slice(&blk);
867            }
868            aes256.encrypt_ctr_batch(base, n, &mut fast);
869            assert_eq!(&fast[..n * 16], &expect256, "n={n} aes256");
870        }
871        // 计数器回绕点(64 块组内回绕 + P2 最大档位跨组回绕)。
872        base[12..16].copy_from_slice(&0xFFFF_FFFDu32.to_be_bytes());
873        let mut fast = vec![0u8; CTR_BATCH_BLOCKS * 16];
874        aes.encrypt_ctr_batch(base, 64, &mut fast);
875        let ctr0 = u32::from_be_bytes(base[12..16].try_into().unwrap());
876        for i in 0..64usize {
877            let mut blk = base;
878            blk[12..16].copy_from_slice(&ctr0.wrapping_add(i as u32).to_be_bytes());
879            aes.encrypt_block(&mut blk);
880            assert_eq!(&fast[i * 16..(i + 1) * 16], &blk, "wrap i={i}");
881        }
882        #[cfg(feature = "simd")]
883        {
884            // 512 块档位:0xFFFFFF00 起第 256 块处回绕,覆盖两个 64-lane 组
885            // 交界与组内回绕(批量入口按 wrapping 语义,与标量参考一致)。
886            let mut base = [
887                0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xff, 0xff,
888                0xff, 0x00,
889            ];
890            let mut fast = vec![0u8; 512 * 16];
891            aes.encrypt_ctr_batch(base, 512, &mut fast);
892            let ctr0 = u32::from_be_bytes(base[12..16].try_into().unwrap());
893            for i in 0..512usize {
894                let mut blk = base;
895                blk[12..16].copy_from_slice(&ctr0.wrapping_add(i as u32).to_be_bytes());
896                aes.encrypt_block(&mut blk);
897                assert_eq!(&fast[i * 16..(i + 1) * 16], &blk, "wrap512 i={i}");
898            }
899            base[12..16].copy_from_slice(&0xFFFF_FFFDu32.to_be_bytes());
900            aes.encrypt_ctr_batch(base, 129, &mut fast);
901            let ctr0 = u32::from_be_bytes(base[12..16].try_into().unwrap());
902            for i in 0..129usize {
903                let mut blk = base;
904                blk[12..16].copy_from_slice(&ctr0.wrapping_add(i as u32).to_be_bytes());
905                aes.encrypt_block(&mut blk);
906                assert_eq!(&fast[i * 16..(i + 1) * 16], &blk, "wrap129 i={i}");
907            }
908        }
909    }
910}