1. AES-128加密引擎的RTL设计

AES-128加密引擎的RTL设计 学习卡片

任务目标

设计一个可综合的AES-128加密引擎RTL模块,支持标准FIPS-197加密流程:完成密钥扩展(生成11轮轮密钥)与10轮轮函数(SubBytes、ShiftRows、MixColumns、AddRoundKey),并通过仿真验证加密结果与NIST标准测试向量一致。

实现方案与文件结构

采用单文件最小可综合实现,顶层模块 aes128_enc 内部例化密钥扩展与轮函数逻辑。文件结构如下:

aes128_enc.v      // 顶层加密引擎(含密钥扩展与轮函数)
aes128_tb.v       // 测试平台:加载标准向量并比对结果

关键完整代码


// aes128_enc.v
module aes128_enc (
    input  wire [127:0] plaintext,
    input  wire [127:0] key,
    output wire [127:0] ciphertext
);
    // 内部信号:11轮轮密钥(每轮128bit)
    reg [127:0] round_key [0:10];
    wire [127:0] state [0:10];

    // 密钥扩展(FIPS-197 第5.2节)
    integer i;
    reg [7:0] rcon [0:10];
    always @(*) begin
        rcon[0] = 8'h01;
        for (i = 1; i < 10; i = i + 1) rcon[i] = rcon[i-1] << 1;
        round_key[0] = key;
        for (i = 1; i <= 10; i = i + 1) begin
            round_key[i] = {round_key[i-1][119:0], 8'h00} ^
                           {sub_word(rot_word(round_key[i-1][127:96])) ^ {24'h000000, rcon[i-1]},
                            round_key[i-1][95:64] ^ sub_word(rot_word(round_key[i-1][127:96])) ^ {24'h000000, rcon[i-1]},
                            round_key[i-1][63:32] ^ sub_word(rot_word(round_key[i-1][127:96])) ^ {24'h000000, rcon[i-1]},
                            round_key[i-1][31:0]  ^ sub_word(rot_word(round_key[i-1][127:96])) ^ {24'h000000, rcon[i-1]}};
        end
    end

    // 轮函数
    assign state[0] = plaintext ^ round_key[0];
    genvar g;
    generate
        for (g = 1; g <= 10; g = g + 1) begin : rounds
            wire [127:0] sub_out, shift_out, mix_out;
            // SubBytes + ShiftRows(合并实现)
            assign sub_out = sub_bytes(state[g-1]);
            assign shift_out = shift_rows(sub_out);
            if (g < 10) begin
                assign mix_out = mix_columns(shift_out);
                assign state[g] = mix_out ^ round_key[g];
            end else begin
                assign state[g] = shift_out ^ round_key[g]; // 最后一轮无MixColumns
            end
        end
    endgenerate
    assign ciphertext = state[10];

    // ---- 子函数定义 ----
    function [7:0] sbox;
        input [7:0] addr;
        reg [7:0] sbox_mem [0:255];
        integer idx;
        begin
            // S-box查找表(FIPS-197 附录A)
            sbox_mem[0] = 8'h63; sbox_mem[1] = 8'h7c; sbox_mem[2] = 8'h77; sbox_mem[3] = 8'h7b;
            sbox_mem[4] = 8'hf2; sbox_mem[5] = 8'h6b; sbox_mem[6] = 8'h6f; sbox_mem[7] = 8'hc5;
            sbox_mem[8] = 8'h30; sbox_mem[9] = 8'h01; sbox_mem[10] = 8'h67; sbox_mem[11] = 8'h2b;
            sbox_mem[12] = 8'hfe; sbox_mem[13] = 8'hd7; sbox_mem[14] = 8'hab; sbox_mem[15] = 8'h76;
            sbox_mem[16] = 8'hca; sbox_mem[17] = 8'h82; sbox_mem[18] = 8'hc9; sbox_mem[19] = 8'h7d;
            sbox_mem[20] = 8'hfa; sbox_mem[21] = 8'h59; sbox_mem[22] = 8'h47; sbox_mem[23] = 8'hf0;
            sbox_mem[24] = 8'had; sbox_mem[25] = 8'hd4; sbox_mem[26] = 8'ha2; sbox_mem[27] = 8'haf;
            sbox_mem[28] = 8'h9c; sbox_mem[29] = 8'ha4; sbox_mem[30] = 8'h72; sbox_mem[31] = 8'hc0;
            sbox_mem[32] = 8'hb7; sbox_mem[33] = 8'hfd; sbox_mem[34] = 8'h93; sbox_mem[35] = 8'h26;
            sbox_mem[36] = 8'h36; sbox_mem[37] = 8'h3f; sbox_mem[38] = 8'hf7; sbox_mem[39] = 8'hcc;
            sbox_mem[40] = 8'h34; sbox_mem[41] = 8'ha5; sbox_mem[42] = 8'he5; sbox_mem[43] = 8'hf1;
            sbox_mem[44] = 8'h71; sbox_mem[45] = 8'hd8; sbox_mem[46] = 8'h31; sbox_mem[47] = 8'h15;
            sbox_mem[48] = 8'h04; sbox_mem[49] = 8'hc7; sbox_mem[50] = 8'h23; sbox_mem[51] = 8'hc3;
            sbox_mem[52] = 8'h18; sbox_mem[53] = 8'h96; sbox_mem[54] = 8'h05; sbox_mem[55] = 8'h9a;
            sbox_mem[56] = 8'h07; sbox_mem[57] = 8'h12; sbox_mem[58] = 8'h80; sbox_mem[59] = 8'he2;
            sbox_mem[60] = 8'heb; sbox_mem[61] = 8'h27; sbox_mem[62] = 8'hb2; sbox_mem[63] = 8'h75;
            sbox_mem[64] = 8'h09; sbox_mem[65] = 8'h83; sbox_mem[66] = 8'h2c; sbox_mem[67] = 8'h1a;
            sbox_mem[68] = 8'h1b; sbox_mem[69] = 8'h6e; sbox_mem[70] = 8'h5a; sbox_mem[71] = 8'ha0;
            sbox_mem[72] = 8'h52; sbox_mem[73] = 8'h3b; sbox_mem[74] = 8'hd6; sbox_mem[75] = 8'hb3;
            sbox_mem[76] = 8'h29; sbox_mem[77] = 8'he3; sbox_mem[78] = 8'h2f; sbox_mem[79] = 8'h84;
            sbox_mem[80] = 8'h53; sbox_mem[81] = 8'hd1; sbox_mem[82] = 8'h00; sbox_mem[83] = 8'hed;
            sbox_mem[84] = 8'h20; sbox_mem[85] = 8'hfc; sbox_mem[86] = 8'hb1; sbox_mem[87] = 8'h5b;
            sbox_mem[88] = 8'h6a; sbox_mem[89] = 8'hcb; sbox_mem[90] = 8'hbe; sbox_mem[91] = 8'h39;
            sbox_mem[92] = 8'h4a; sbox_mem[93] = 8'h4c; sbox_mem[94] = 8'h58; sbox_mem[95] = 8'hcf;
            sbox_mem[96] = 8'hd0; sbox_mem[97] = 8'hef; sbox_mem[98] = 8'haa; sbox_mem[99] = 8'hfb;
            sbox_mem[100] = 8'h43; sbox_mem[101] = 8'h4d; sbox_mem[102] = 8'h33; sbox_mem[103] = 8'h85;
            sbox_mem[104] = 8'h45; sbox_mem[105] = 8'hf9; sbox_mem[106] = 8'h02; sbox_mem[107] = 8'h7f;
            sbox_mem[108] = 8'h50; sbox_mem[109] = 8'h3c; sbox_mem[110] = 8'h9f; sbox_mem[111] = 8'ha8;
            sbox_mem[112] = 8'h51; sbox_mem[113] = 8'ha3; sbox_mem[114] = 8'h40; sbox_mem[115] = 8'h8f;
            sbox_mem[116] = 8'h92; sbox_mem[117] = 8'h9d; sbox_mem[118] = 8'h38; sbox_mem[119] = 8'hf5;
            sbox_mem[120] = 8'hbc; sbox_mem[121] = 8'hb6; sbox_mem[122] = 8'hda; sbox_mem[123] = 8'h21;
            sbox_mem[124] = 8'h10; sbox_mem[125] = 8'hff; sbox_mem[126] = 8'hf3; sbox_mem[127] = 8'hd2;
            sbox_mem[128] = 8'hcd; sbox_mem[129] = 8'h0c; sbox_mem[130] = 8'h13; sbox_mem[131] = 8'hec;
            sbox_mem[132] = 8'h5f; sbox_mem[133] = 8'h97; sbox_mem[134] = 8'h44; sbox_mem[135] = 8'h17;
            sbox_mem[136] = 8'hc4; sbox_mem[137] = 8'ha7; sbox_mem[138] = 8'h7e; sbox_mem[139] = 8'h3d;
            sbox_mem[140] = 8'h64; sbox_mem[141] = 8'h5d; sbox_mem[142] = 8'h19; sbox_mem[143] = 8'h73;
            sbox_mem[144] = 8'h60; sbox_mem[145] = 8'h81; sbox_mem[146] = 8'h4f; sbox_mem[147] = 8'hdc;
            sbox_mem[148] = 8'h22; sbox_mem[149] = 8'h2a; sbox_mem[150] = 8'h90; sbox_mem[151] = 8'h88;
            sbox_mem[152] = 8'h46; sbox_mem[153] = 8'hee; sbox_mem[154] = 8'hb8; sbox_mem[155] = 8'h14;
            sbox_mem[156] = 8'hde; sbox_mem[157] = 8'h5e; sbox_mem[158] = 8'h0b; sbox_mem[159] = 8'hdb;
            sbox_mem[160] = 8'he0; sbox_mem[161] = 8'h32; sbox_mem[162] = 8'h3a; sbox_mem[163] = 8'h0a;
            sbox_mem[164] = 8'h49; sbox_mem[165] = 8'h06; sbox_mem[166] = 8'h24; sbox_mem[167] = 8'h5c;
            sbox_mem[168] = 8'hc2; sbox_mem[169] = 8'hd3; sbox_mem[170] = 8'hac; sbox_mem[171] = 8'h62;
            sbox_mem[172] = 8'h91; sbox_mem[173] = 8'h95; sbox_mem[174] = 8'he4; sbox_mem[175] = 8'h79;
            sbox_mem[176] = 8'he7; sbox_mem[177] = 8'hc8; sbox_mem[178] = 8'h37; sbox_mem[179] = 8'h6d;
            sbox_mem[180] = 8'h8d; sbox_mem[181] = 8'hd5; sbox_mem[182] = 8'h4e; sbox_mem[183] = 8'ha9;
            sbox_mem[184] = 8'h6c; sbox_mem[185] = 8'h56; sbox_mem[186] = 8'hf4; sbox_mem[187] = 8'hea;
            sbox_mem[188] = 8'h65; sbox_mem[189] = 8'h7a; sbox_mem[190] = 8'hae; sbox_mem[191] = 8'h08;
            sbox_mem[192] = 8'hba; sbox_mem[193] = 8'h78; sbox_mem[194] = 8'h25; sbox_mem[195] = 8'h2e;
            sbox_mem[196] = 8'h1c; sbox_mem[197] = 8'ha6; sbox_mem[198] = 8'hb4; sbox_mem[199] = 8'hc6;
            sbox_mem[200] = 8'he8; sbox_mem[201] = 8'hdd; sbox_mem[202] = 8'h74; sbox_mem[203] = 8'h1f;
            sbox_mem[204] = 8'h4b; sbox_mem[205] = 8'hbd; sbox_mem[206] = 8'h8b; sbox_mem[207] = 8'h8a;
            sbox_mem[208] = 8'h70; sbox_mem[209] = 8'h3e; sbox_mem[210] = 8'hb5; sbox_mem[211] = 8'h66;
            sbox_mem[212] = 8'h48; sbox_mem[213] = 8'h03; sbox_mem[214] = 8'hf6; sbox_mem[215] = 8'h0e;
            sbox_mem[216] = 8'h61; sbox_mem[217] = 8'h35; sbox_mem[218] = 8'h57; sbox_mem[219] = 8'hb9;
            sbox_mem[220] = 8'h86; sbox_mem[221] = 8'hc1; sbox_mem[222] = 8'h1d; sbox_mem[223] = 8'h9e;
            sbox_mem[224] = 8'he1; sbox_mem[225] = 8'hf8; sbox_mem[226] = 8'h98; sbox_mem[227] = 8'h11;
            sbox_mem[228] = 8'h69; sbox_mem[229] = 8'hd9; sbox_mem[230] = 8'h8e; sbox_mem[231] = 8'h94;
            sbox_mem[232] = 8'h9b; sbox_mem[233] = 8'h1e; sbox_mem[234] = 8'h87; sbox_mem[235] = 8'he9;
            sbox_mem[236] = 8'hce; sbox_mem[237] = 8'h55; sbox_mem[238] = 8'h28; sbox_mem[239] = 8'hdf;
            sbox_mem[240] = 8'h8c; sbox_mem[241] = 8'ha1; sbox_mem[242] = 8'h89; sbox_mem[243] = 8'h0d;
            sbox_mem[244] = 8'hbf; sbox_mem[245] = 8'he6; sbox_mem[246] = 8'h42; sbox_mem[247] = 8'h68;
            sbox_mem[248] = 8'h41; sbox_mem[249] = 8'h99; sbox_mem[250] = 8'h2d; sbox_mem[251] = 8'h0f;
            sbox_mem[252] = 8'hb0; sbox_mem[253] = 8'h54; sbox_mem[254] = 8'hbb; sbox_mem[255] = 8'h16;
            sbox = sbox_mem[addr];
        end
    endfunction

    function [127:0] sub_bytes;
        input [127:0] data;
        integer b;
        begin
            for (b = 0; b < 16; b = b + 1)
                sub_bytes[b*8 +: 8] = sbox(data[b*8 +: 8]);
        end
    endfunction

    function [127:0] shift_rows;
        input [127:0] data;
        reg [127:0] tmp;
        integer r, c;
        begin
            // 状态矩阵按列存储:data[127:120]=S0, data[119:112]=S1, ... data[7:0]=S15
            // 行移位:第r行循环左移r字节
            for (r = 0; r < 4; r = r + 1)
                for (c = 0; c < 4; c = c + 1)
                    tmp[(r*4+c)*8 +: 8] = data[((r*4 + ((c+r)%4)))*8 +: 8];
            shift_rows = tmp;
        end
    endfunction

    function [127:0] mix_columns;
        input [127:0] data;
        reg [7:0] col [0:3];
        reg [7:0] out_col [0:3];
        integer c, i;
        begin
            for (c = 0; c < 4; c = c + 1) begin
                for (i = 0; i < 4; i = i + 1)
                    col[i] = data[(c*4+i)*8 +: 8];
                // 列混合矩阵乘法(GF(2^8))
                out_col[0] = xtime(col[0]) ^ (xtime(col[1]) ^ col[1]) ^ col[2] ^ col[3];
                out_col[1] = col[0] ^ xtime(col[1]) ^ (xtime(col[2]) ^ col[2]) ^ col[3];
                out_col[2] = col[0] ^ col[1] ^ xtime(col[2]) ^ (xtime(col[3]) ^ col[3]);
                out_col[3] = (xtime(col[0]) ^ col[0]) ^ col[1] ^ col[2] ^ xtime(col[3]);
                for (i = 0; i < 4; i = i + 1)
                    mix_columns[(c*4+i)*8 +: 8] = out_col[i];
            end
        end
    endfunction

    function [7:0] xtime;
        input [7:0] x;
        begin
            xtime = {x[6:0], 1'b0} ^ (x[7] ? 8'h1b : 8'h00);
        end
    endfunction

    function [31:0] rot_word;
        input [31:0] w;
        begin
            rot_word = {w[23:0], w[31:24]};
        end
    endfunction

    function [31:0] sub_word;
        input [31:0] w;
        integer b;
        begin
            for (b = 0; b < 4; b = b + 1)
                sub_word[b*8 +: 8] = sbox(w[b*8 +: 8]);
        end
    endfunction
endmodule

仿真测试平台


// aes128_tb.v
`timescale 1ns/1ps
module aes128_tb;
    reg [127:0] pt, key;
    wire [127:0] ct;

    aes128_enc dut(.plaintext(pt), .key(key), .ciphertext(ct));

    initial begin
        // FIPS-197 附录B 标准向量
        pt = 128'h00112233445566778899aabbccddeeff;
        key = 128'h000102030405060708090a0b0c0d0e0f;
        #10;
        if (ct === 128'h69c4e0d86a7b0430d8cdb78070b4c55a)
            $display("PASS: AES-128 encryption matches FIPS-197 vector");
        else
            $display("FAIL: got %h, expected 69c4e0d86a7b0430d8cdb78070b4c55a", ct);
        $finish;
    end
endmodule

运行与验证

  1. 仿真运行:使用Icarus Verilog执行以下命令:
iverilog -o aes128_sim aes128_enc.v aes128_tb.v
vvp aes128_sim
  1. 通过条件:控制台输出 PASS: AES-128 encryption matches FIPS-197 vector,且无编译错误。
  2. 综合验证(可选):若使用Vivado/Quartus,将 aes128_enc.v 设为顶层并运行综合,确认无latch推断且资源报告正常生成。

设计说明

本实现采用组合逻辑完成全部10轮加密,密钥扩展与轮函数均为纯组合电路,因此输出 ciphertext 在输入稳定后立即有效(无时钟边沿)。S-box查找表完整实现FIPS-197附录A数值,列混合使用xtime辅助函数完成GF(2^8)乘法。测试平台使用NIST标准向量(明文 00112233445566778899aabbccddeeff,密钥 000102030405060708090a0b0c0d0e0f),预期密文为 69c4e0d86a7b0430d8cdb78070b4c55a。若需时序版本,可在顶层添加寄存器级流水,但本案例聚焦组合逻辑正确性验证。

AES-128加密引擎数据通路 明文 (128-bit) 密钥 (128-bit) AddRoundKey(0) 轮函数 ×10 SubBytes ShiftRows MixColumns AddRoundKey(i) 最后一轮跳过MixColumns 密钥扩展 生成11个轮密钥 (128-bit × 11) 密文 (128-bit) 循环10次