阶段一对称密码基础 — AES 加密的每一轮由四个操作组成:SubBytes → ShiftRows → MixColumns → AddRoundKey。理解每一层的硬件映射是构建完整 AES 引擎的基础。
对状态矩阵的每个字节独立施加 S-Box 非线性变换。这是 AES 唯一的非线性操作,提供混淆性。
状态矩阵(4×4 字节):
[s0 s4 s8 s12]
[s1 s5 s9 s13]
[s2 s6 s10 s14]
[s3 s7 s11 s15]
SubBytes: si → S(si),16 个 S-Box 并行工作
对状态矩阵的行进行不同量的循环左移:
| 行号 | 左移字节数 |
|---|---|
| 0 | 0 |
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
这实现了列间的扩散——将同一列的字节分散到不同列。
对状态矩阵的每列进行 GF(2⁸) 上的矩阵乘法:
这是 AES 中最复杂的操作,需要 GF(2⁸) 乘法。
将当前状态与轮密钥逐位异或:
MixColumns 需要 GF(2⁸) 上乘以 2(xtime)和乘以 3 的运算:
// gf_mul.v - GF(2^8) 乘法模块(MixColumns 所需)
module gf_mul2 (
input wire [7:0] a,
output wire [7:0] y
);
// 乘以 2 = 左移1位,若最高位为1则异或 0x1B
assign y = (a[7]) ? ({a[6:0], 1'b0} ^ 8'h1b) : {a[6:0], 1'b0};
endmodule
module gf_mul3 (
input wire [7:0] a,
output wire [7:0] y
);
// 乘以 3 = 乘以 2 + 乘以 1 = (2a) XOR a
wire [7:0] a2;
gf_mul2 u_mul2 (.a(a), .y(a2));
assign y = a2 ^ a;
endmodule
// aes_mixcol.v - AES MixColumns 单列处理模块
module aes_mixcol (
input wire [7:0] s0, s1, s2, s3, // 输入列的4个字节
output wire [7:0] d0, d1, d2, d3 // 输出列的4个字节
);
// GF(2^8) 乘法
wire [7:0] s0_2, s1_2, s2_2, s3_2; // 2*s
wire [7:0] s0_3, s1_3, s2_3, s3_3; // 3*s
gf_mul2 m20 (.a(s0), .y(s0_2));
gf_mul2 m21 (.a(s1), .y(s1_2));
gf_mul2 m22 (.a(s2), .y(s2_2));
gf_mul2 m23 (.a(s3), .y(s3_2));
gf_mul3 m30 (.a(s0), .y(s0_3));
gf_mul3 m31 (.a(s1), .y(s1_3));
gf_mul3 m32 (.a(s2), .y(s2_3));
gf_mul3 m33 (.a(s3), .y(s3_3));
// 矩阵乘法
assign d0 = s0_2 ^ s1_3 ^ s2 ^ s3;
assign d1 = s0 ^ s1_2 ^ s2_3 ^ s3;
assign d2 = s0 ^ s1 ^ s2_2 ^ s3_3;
assign d3 = s0_3 ^ s1 ^ s2 ^ s3_2;
endmodule
ShiftRows 是纯连线操作,只需重新排列字节顺序,零逻辑资源消耗:
// aes_shiftrows.v - AES ShiftRows 操作
module aes_shiftrows (
input wire [127:0] state_in,
output wire [127:0] state_out
);
// 状态矩阵按列存储:
// [s0 s4 s8 s12] Row 0: 不移位
// [s1 s5 s9 s13] Row 1: 左移1
// [s2 s6 s10 s14] Row 2: 左移2
// [s3 s7 s11 s15] Row 3: 左移3
// Row 0: 不变
assign state_out[127:120] = state_in[127:120]; // s0
assign state_out[95:88] = state_in[95:88]; // s4
assign state_out[63:56] = state_in[63:56]; // s8
assign state_out[31:24] = state_in[31:24]; // s12
// Row 1: 左移1字节
assign state_out[119:112] = state_in[87:80]; // s5 → 位置1
assign state_out[87:80] = state_in[55:48]; // s9 → 位置5
assign state_out[55:48] = state_in[23:16]; // s13→ 位置9
assign state_out[23:16] = state_in[119:112]; // s1 → 位置13
// Row 2: 左移2字节
assign state_out[111:104] = state_in[47:40]; // s10→ 位置2
assign state_out[79:72] = state_in[15:8]; // s14→ 位置6
assign state_out[47:40] = state_in[111:104]; // s2 → 位置10
assign state_out[15:8] = state_in[79:72]; // s6 → 位置14
// Row 3: 左移3字节
assign state_out[103:96] = state_in[7:0]; // s15→ 位置3
assign state_out[71:64] = state_in[103:96]; // s3 → 位置7
assign state_out[39:32] = state_in[71:64]; // s7 → 位置11
assign state_out[7:0] = state_in[39:32]; // s11→ 位置15
endmodule
// aes_round.v - AES 单轮加密操作
module aes_round (
input wire [127:0] state_in,
input wire [127:0] round_key,
input wire final_round, // 最后一轮跳过 MixColumns
output wire [127:0] state_out
);
// Step 1: SubBytes - 16 个 S-Box 并行
wire [7:0] sb [0:15];
genvar i;
generate
for (i = 0; i < 16; i = i + 1) begin : gen_sbox
aes_sbox_lut u_sbox (
.addr(state_in[i*8+7 -: 8]),
.data(sb[i])
);
end
endgenerate
wire [127:0] after_sub = {sb[15],sb[14],sb[13],sb[12],
sb[11],sb[10],sb[9],sb[8],
sb[7],sb[6],sb[5],sb[4],
sb[3],sb[2],sb[1],sb[0]};
// Step 2: ShiftRows
wire [127:0] after_shift;
aes_shiftrows u_shift (.state_in(after_sub), .state_out(after_shift));
// Step 3: MixColumns(最后一轮跳过)
wire [127:0] after_mix;
aes_mixcol mc0 (.s0(after_shift[127:120]), .s1(after_shift[119:112]),
.s2(after_shift[111:104]), .s3(after_shift[103:96]),
.d0(after_mix[127:120]), .d1(after_mix[119:112]),
.d2(after_mix[111:104]), .d3(after_mix[103:96]));
aes_mixcol mc1 (.s0(after_shift[95:88]), .s1(after_shift[87:80]),
.s2(after_shift[79:72]), .s3(after_shift[71:64]),
.d0(after_mix[95:88]), .d1(after_mix[87:80]),
.d2(after_mix[79:72]), .d3(after_mix[71:64]));
aes_mixcol mc2 (.s0(after_shift[63:56]), .s1(after_shift[55:48]),
.s2(after_shift[47:40]), .s3(after_shift[39:32]),
.d0(after_mix[63:56]), .d1(after_mix[55:48]),
.d2(after_mix[47:40]), .d3(after_mix[39:32]));
aes_mixcol mc3 (.s0(after_shift[31:24]), .s1(after_shift[23:16]),
.s2(after_shift[15:8]), .s3(after_shift[7:0]),
.d0(after_mix[31:24]), .d1(after_mix[23:16]),
.d2(after_mix[15:8]), .d3(after_mix[7:0]));
// Step 4: AddRoundKey
// 最后一轮跳过 MixColumns,直接对 ShiftRows 结果异或轮密钥
assign state_out = final_round ?
(after_shift ^ round_key) :
(after_mix ^ round_key);
endmodule
// aes_round_tb.v - AES 单轮测试
module aes_round_tb;
reg [127:0] state_in, round_key;
reg final_round;
wire [127:0] state_out;
aes_round uut (
.state_in(state_in), .round_key(round_key),
.final_round(final_round), .state_out(state_out)
);
initial begin
// NIST Appendix B 中间状态测试
state_in = 128'h00102030405060708090a0b0c0d0e0f0;
round_key = 128'h2b7e151628aed2a6abf7158809cf4f3c;
final_round = 0;
#10;
$display("Round output: %032h", state_out);
// 最后一轮测试
final_round = 1;
#10;
$display("Final round: %032h", state_out);
$finish;
end
endmodule
1. 手动计算 SubBytes(0x00) = ?,ShiftRows 后位置如何变化?
2. 验证 MixColumns 的一个列:输入 [0xdb, 0x13, 0x53, 0x22],输出应为 [0x8e, 0x4d, 0xa1, 0xbc]。
3. 解释为什么最后一轮省略 MixColumns 不影响安全性(提示:考虑 ShiftRows 和 MixColumns 的交互)。
4. 计算 MixColumns 一个列的临界路径延迟,假设 S-Box 延迟 2ns,GF 乘法延迟 1ns,XOR 延迟 0.5ns。
你已实现 AES 加密轮的全部四个操作——SubBytes、ShiftRows、MixColumns、AddRoundKey,并理解了每一层的硬件映射和 GF(2⁸) 运算。轮函数是 AES 的核心引擎!
获得徽章:⚙️ ROUND_MASTER
推荐使用以下工具链进行课程实践:
# 安装 Verilator
sudo apt install verilator
# 安装 Icarus Verilog(可选)
sudo apt install iverilog
# 安装 GTKWave(波形查看器)
sudo apt install gtkwave
# 验证安装
verilator --lint-only --version
iverilog -V
密码学硬件实现的关键性能指标:
这些指标之间通常存在 trade-off,设计时需根据应用场景权衡。
MixColumns 中乘以 2 的运算称为 xtime:
xtime(a) = a << 1 if a[7] == 0
= (a << 1) ^ 0x1B if a[7] == 1
0x1B 是不可约多项式 x⁸ + x⁴ + x³ + x + 1 的低 8 位。当左移导致溢出(第 7 位为 1)时,需要异或 0x1B 将结果约回 GF(2⁸)。
3 × a = (2 × a) ⊕ a = xtime(a) ⊕ a
这只需要一次 xtime 和一次 XOR,非常高效。
AES 的 MixColumns 矩阵是循环矩阵 M = circ(2,3,1,1)。这个矩阵的选择满足:
本课涉及的核心概念和技术关系:
Verilog 仿真调试的常用方法:
// 调试示例
initial begin
$dumpfile("sim.vcd");
$dumpvars(0, uut);
end
// 断言验证
assert property (@(posedge clk) valid |-> data !== 'x)
else $error("Invalid data when valid!");
# 1. 语法检查
verilator --lint-only module.v
# 2. 创建 C++ 测试主函数
cat > sim_main.cpp << 'EOF'
#include "Vmodule.h"
#include "verilated.h"
int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
Vmodule* top = new Vmodule;
top->clk = 0; top->rst_n = 0;
top->eval();
top->rst_n = 1;
for (int i = 0; i < 100; i++) {
top->clk = !top->clk;
top->eval();
}
delete top;
return 0;
}
EOF
# 3. 编译
verilator -cc module.v --exe sim_main.cpp
make -C obj_dir -f Vmodule.mk
# 4. 运行
./obj_dir/Vmodule
密码硬件的性能评估维度:
| 指标 | 单位 | 说明 |
|---|---|---|
| 面积 | GE / LUT | 等效门数或查找表数量 |
| 频率 | MHz | 最大时钟频率 |
| 吞吐量 | Gbps | 每秒处理的数据量 |
| 延迟 | 周期数 | 从输入到输出的周期 |
| 能效 | pJ/bit | 每比特能耗 |
| 面积效率 | Gbps/GE | 单位面积吞吐量 |
不同应用场景对指标优先级不同:IoT 偏重面积和能效,服务器偏重吞吐量。