第04课:AES 加密轮

阶段一对称密码基础 — AES 加密的每一轮由四个操作组成:SubBytes → ShiftRows → MixColumns → AddRoundKey。理解每一层的硬件映射是构建完整 AES 引擎的基础。

1. AES 加密轮的四层操作

1.1 SubBytes

对状态矩阵的每个字节独立施加 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 并行工作

1.2 ShiftRows

对状态矩阵的行进行不同量的循环左移:

行号左移字节数
00
11
22
33

这实现了列间的扩散——将同一列的字节分散到不同列。

1.3 MixColumns

对状态矩阵的每列进行 GF(2⁸) 上的矩阵乘法:

[s'₀] [2 3 1 1] [s₀]
[s'₁] = [1 2 3 1] [s₁]
[s'₂] [1 1 2 3] [s₂]
[s'₃] [3 1 1 2] [s₃]

这是 AES 中最复杂的操作,需要 GF(2⁸) 乘法。

1.4 AddRoundKey

将当前状态与轮密钥逐位异或:

State' = State ⊕ RoundKey

2. GF(2⁸) 乘法硬件实现

MixColumns 需要 GF(2⁸) 上乘以 2(xtime)和乘以 3 的运算:

✅Verilator验证通过
// 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

3. MixColumns 硬件实现

✅Verilator验证通过
// 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

4. ShiftRows 硬件实现

ShiftRows 是纯连线操作,只需重新排列字节顺序,零逻辑资源消耗:

✅Verilator验证通过
// 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

5. 完整 AES 加密轮模块

✅Verilator验证通过
// 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

6. 仿真验证

// 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,设计时需根据应用场景权衡。

5. MixColumns 的 GF(2⁸) 运算详解

5.1 xtime 运算

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⁸)。

5.2 乘以 3 = 乘以 (2+1)

3 × a = (2 × a) ⊕ a = xtime(a) ⊕ a

这只需要一次 xtime 和一次 XOR,非常高效。

5.3 MixColumns 矩阵的选择

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!");

🔧 Verilator 编译仿真完整流程

# 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 偏重面积和能效,服务器偏重吞吐量。