4. AES-128密钥扩展模块优化
任务目标
在FPGA上实现AES-128密钥扩展模块,通过流水线化密钥调度器消除关键路径上的组合逻辑延迟,并实现密钥调度与加密轮次并行工作,使每一轮加密无需等待密钥扩展完成即可获取轮密钥。
环境与依赖
- 硬件平台:任意支持Verilog的FPGA(如Xilinx Artix-7、Intel Cyclone V)
- 工具链:Vivado / Quartus / Icarus Verilog(仿真)
- 无额外IP依赖,纯RTL实现
设计思路
AES-128密钥扩展共需生成11个轮密钥(含初始轮密钥)。传统实现中,密钥扩展与加密轮串行执行,每轮加密需等待当前轮密钥生成完毕,导致关键路径包含S-box替换与异或逻辑,组合延迟较大。本设计将密钥扩展拆分为两级流水线:轮常数生成与轮密钥计算,使密钥调度器提前一轮计算出后续轮密钥,加密轮直接取用已就绪的轮密钥,实现并行处理。
关键完整代码
// AES-128 流水线密钥扩展模块
// 输入:initial_key[127:0],输出:round_key[127:0](当前轮密钥)
// 流水线深度:2级,密钥调度提前一轮完成
module key_expand_pipeline (
input wire clk,
input wire rst_n,
input wire key_valid, // 初始密钥有效标志
input wire [127:0] initial_key,
output reg [127:0] round_key, // 当前轮密钥输出
output reg key_ready // 轮密钥就绪标志
);
// 内部状态
reg [127:0] key_reg; // 当前轮密钥寄存器
reg [3:0] round_cnt; // 当前轮计数 0~10
reg [127:0] next_key; // 下一轮密钥(流水线第1级输出)
reg [7:0] rcon; // 轮常数
// S-box 查找表(仅用于密钥扩展中的 SubWord)
function [7:0] sbox;
input [7:0] addr;
case (addr)
8'h00: sbox = 8'h63; 8'h01: sbox = 8'h7c; 8'h02: sbox = 8'h77;
8'h03: sbox = 8'h7b; 8'h04: sbox = 8'hf2; 8'h05: sbox = 8'h6b;
8'h06: sbox = 8'h6f; 8'h07: sbox = 8'hc5; 8'h08: sbox = 8'h30;
8'h09: sbox = 8'h01; 8'h0a: sbox = 8'h67; 8'h0b: sbox = 8'h2b;
8'h0c: sbox = 8'hfe; 8'h0d: sbox = 8'hd7; 8'h0e: sbox = 8'hab;
8'h0f: sbox = 8'h76; 8'h10: sbox = 8'hca; 8'h11: sbox = 8'h82;
8'h12: sbox = 8'hc9; 8'h13: sbox = 8'h7d; 8'h14: sbox = 8'hfa;
8'h15: sbox = 8'h59; 8'h16: sbox = 8'h47; 8'h17: sbox = 8'hf0;
8'h18: sbox = 8'had; 8'h19: sbox = 8'hd4; 8'h1a: sbox = 8'ha2;
8'h1b: sbox = 8'haf; 8'h1c: sbox = 8'h9c; 8'h1d: sbox = 8'ha4;
8'h1e: sbox = 8'h72; 8'h1f: sbox = 8'hc0; 8'h20: sbox = 8'hb7;
8'h21: sbox = 8'hfd; 8'h22: sbox = 8'h93; 8'h23: sbox = 8'h26;
8'h24: sbox = 8'h36; 8'h25: sbox = 8'h3f; 8'h26: sbox = 8'hf7;
8'h27: sbox = 8'hcc; 8'h28: sbox = 8'h34; 8'h29: sbox = 8'ha5;
8'h2a: sbox = 8'he5; 8'h2b: sbox = 8'hf1; 8'h2c: sbox = 8'h71;
8'h2d: sbox = 8'hd8; 8'h2e: sbox = 8'h31; 8'h2f: sbox = 8'h15;
8'h30: sbox = 8'h04; 8'h31: sbox = 8'hc7; 8'h32: sbox = 8'h23;
8'h33: sbox = 8'hc3; 8'h34: sbox = 8'h18; 8'h35: sbox = 8'h96;
8'h36: sbox = 8'h05; 8'h37: sbox = 8'h9a; 8'h38: sbox = 8'h07;
8'h39: sbox = 8'h12; 8'h3a: sbox = 8'h80; 8'h3b: sbox = 8'he2;
8'h3c: sbox = 8'heb; 8'h3d: sbox = 8'h27; 8'h3e: sbox = 8'hb2;
8'h3f: sbox = 8'h75; 8'h40: sbox = 8'h09; 8'h41: sbox = 8'h83;
8'h42: sbox = 8'h2c; 8'h43: sbox = 8'h1a; 8'h44: sbox = 8'h1b;
8'h45: sbox = 8'h6e; 8'h46: sbox = 8'h5a; 8'h47: sbox = 8'ha0;
8'h48: sbox = 8'h52; 8'h49: sbox = 8'h3b; 8'h4a: sbox = 8'hd6;
8'h4b: sbox = 8'hb3; 8'h4c: sbox = 8'h29; 8'h4d: sbox = 8'he3;
8'h4e: sbox = 8'h2f; 8'h4f: sbox = 8'h84; 8'h50: sbox = 8'h53;
8'h51: sbox = 8'hd1; 8'h52: sbox = 8'h00; 8'h53: sbox = 8'hed;
8'h54: sbox = 8'h20; 8'h55: sbox = 8'hfc; 8'h56: sbox = 8'hb1;
8'h57: sbox = 8'h5b; 8'h58: sbox = 8'h6a; 8'h59: sbox = 8'hcb;
8'h5a: sbox = 8'hbe; 8'h5b: sbox = 8'h39; 8'h5c: sbox = 8'h4a;
8'h5d: sbox = 8'h4c; 8'h5e: sbox = 8'h58; 8'h5f: sbox = 8'hcf;
8'h60: sbox = 8'hd0; 8'h61: sbox = 8'hef; 8'h62: sbox = 8'haa;
8'h63: sbox = 8'hfb; 8'h64: sbox = 8'h43; 8'h65: sbox = 8'h4d;
8'h66: sbox = 8'h33; 8'h67: sbox = 8'h85; 8'h68: sbox = 8'h45;
8'h69: sbox = 8'hf9; 8'h6a: sbox = 8'h02; 8'h6b: sbox = 8'h7f;
8'h6c: sbox = 8'h50; 8'h6d: sbox = 8'h3c; 8'h6e: sbox = 8'h9f;
8'h6f: sbox = 8'ha8; 8'h70: sbox = 8'h51; 8'h71: sbox = 8'ha3;
8'h72: sbox = 8'h40; 8'h73: sbox = 8'h8f; 8'h74: sbox = 8'h92;
8'h75: sbox = 8'h9d; 8'h76: sbox = 8'h38; 8'h77: sbox = 8'hf5;
8'h78: sbox = 8'hbc; 8'h79: sbox = 8'hb6; 8'h7a: sbox = 8'hda;
8'h7b: sbox = 8'h21; 8'h7c: sbox = 8'h10; 8'h7d: sbox = 8'hff;
8'h7e: sbox = 8'hf3; 8'h7f: sbox = 8'hd2; 8'h80: sbox = 8'hcd;
8'h81: sbox = 8'h0c; 8'h82: sbox = 8'h13; 8'h83: sbox = 8'hec;
8'h84: sbox = 8'h5f; 8'h85: sbox = 8'h97; 8'h86: sbox = 8'h44;
8'h87: sbox = 8'h17; 8'h88: sbox = 8'hc4; 8'h89: sbox = 8'ha7;
8'h8a: sbox = 8'h7e; 8'h8b: sbox = 8'h3d; 8'h8c: sbox = 8'h64;
8'h8d: sbox = 8'h5d; 8'h8e: sbox = 8'h19; 8'h8f: sbox = 8'h73;
8'h90: sbox = 8'h60; 8'h91: sbox = 8'h81; 8'h92: sbox = 8'h4f;
8'h93: sbox = 8'hdc; 8'h94: sbox = 8'h22; 8'h95: sbox = 8'h2a;
8'h96: sbox = 8'h90; 8'h97: sbox = 8'h88; 8'h98: sbox = 8'h46;
8'h99: sbox = 8'hee; 8'h9a: sbox = 8'hb8; 8'h9b: sbox = 8'h14;
8'h9c: sbox = 8'hde; 8'h9d: sbox = 8'h5e; 8'h9e: sbox = 8'h0b;
8'h9f: sbox = 8'hdb; 8'ha0: sbox = 8'he0; 8'ha1: sbox = 8'h32;
8'ha2: sbox = 8'h3a; 8'ha3: sbox = 8'h0a; 8'ha4: sbox = 8'h49;
8'ha5: sbox = 8'h06; 8'ha6: sbox = 8'h24; 8'ha7: sbox = 8'h5c;
8'ha8: sbox = 8'hc2; 8'ha9: sbox = 8'hd3; 8'haa: sbox = 8'hac;
8'hab: sbox = 8'h62; 8'hac: sbox = 8'h91; 8'had: sbox = 8'h95;
8'hae: sbox = 8'he4; 8'haf: sbox = 8'h79; 8'hb0: sbox = 8'he7;
8'hb1: sbox = 8'hc8; 8'hb2: sbox = 8'h37; 8'hb3: sbox = 8'h6d;
8'hb4: sbox = 8'h8d; 8'hb5: sbox = 8'hd5; 8'hb6: sbox = 8'h4e;
8'hb7: sbox = 8'ha9; 8'hb8: sbox = 8'h6c; 8'hb9: sbox = 8'h56;
8'hba: sbox = 8'hf4; 8'hbb: sbox = 8'hea; 8'hbc: sbox = 8'h65;
8'hbd: sbox = 8'h7a; 8'hbe: sbox = 8'hae; 8'hbf: sbox = 8'h08;
8'hc0: sbox = 8'hba; 8'hc1: sbox = 8'h78; 8'hc2: sbox = 8'h25;
8'hc3: sbox = 8'h2e; 8'hc4: sbox = 8'h1c; 8'hc5: sbox = 8'ha6;
8'hc6: sbox = 8'hb4; 8'hc7: sbox = 8'hc6; 8'hc8: sbox = 8'he8;
8'hc9: sbox = 8'hdd; 8'hca: sbox = 8'h74; 8'hcb: sbox = 8'h1f;
8'hcc: sbox = 8'h4b; 8'hcd: sbox = 8'hbd; 8'hce: sbox = 8'h8b;
8'hcf: sbox = 8'h8a; 8'hd0: sbox = 8'h70; 8'hd1: sbox = 8'h3e;
8'hd2: sbox = 8'hb5; 8'hd3: sbox = 8'h66; 8'hd4: sbox = 8'h48;
8'hd5: sbox = 8'h03; 8'hd6: sbox = 8'hf6; 8'hd7: sbox = 8'h0e;
8'hd8: sbox = 8'h61; 8'hd9: sbox = 8'h35; 8'hda: sbox = 8'h57;
8'hdb: sbox = 8'hb9; 8'hdc: sbox = 8'h86; 8'hdd: sbox = 8'hc1;
8'hde: sbox = 8'h1d; 8'hdf: sbox = 8'h9e; 8'he0: sbox = 8'he1;
8'he1: sbox = 8'hf8; 8'he2: sbox = 8'h98; 8'he3: sbox = 8'h11;
8'he4: sbox = 8'h69; 8'he5: sbox = 8'hd9; 8'he6: sbox = 8'h8e;
8'he7: sbox = 8'h94; 8'he8: sbox = 8'h9b; 8'he9: sbox = 8'h1e;
8'hea: sbox = 8'h87; 8'heb: sbox = 8'he9; 8'hec: sbox = 8'hce;
8'hed: sbox = 8'h55; 8'hee: sbox = 8'h28; 8'hef: sbox = 8'hdf;
8'hf0: sbox = 8'h8c; 8'hf1: sbox = 8'ha1; 8'hf2: sbox = 8'h89;
8'hf3: sbox = 8'h0d; 8'hf4: sbox = 8'hbf; 8'hf5: sbox = 8'he6;
8'hf6: sbox = 8'h42; 8'hf7: sbox = 8'h68; 8'hf8: sbox = 8'h41;
8'hf9: sbox = 8'h99; 8'hfa: sbox = 8'h2d; 8'hfb: sbox = 8'h0f;
8'hfc: sbox = 8'hb0; 8'hfd: sbox = 8'h54; 8'hfe: sbox = 8'hbb;
8'hff: sbox = 8'h16;
default: sbox = 8'h00;
endcase
endfunction
// RotWord: 循环左移1字节
function [31:0] rot_word;
input [31:0] w;
rot_word = {w[23:0], w[31:24]};
endfunction
// SubWord: 对4字节分别S-box替换
function [31:0] sub_word;
input [31:0] w;
sub_word = {sbox(w[31:24]), sbox(w[23:16]), sbox(w[15:8]), sbox(w[7:0])};
endfunction
// 轮常数生成(组合逻辑)
function [7:0] get_rcon;
input [3:0] round;
case (round)
4'd1: get_rcon = 8'h01;
4'd2: get_rcon = 8'h02;
4'd3: get_rcon = 8'h04;
4'd4: get_rcon = 8'h08;
4'd5: get_rcon = 8'h10;
4'd6: get_rcon = 8'h20;
4'd7: get_rcon = 8'h40;
4'd8: get_rcon = 8'h80;
4'd9: get_rcon = 8'h1b;
4'd10: get_rcon = 8'h36;
default: get_rcon = 8'h00;
endcase
endfunction
// 流水线第1级:计算下一轮密钥(组合逻辑)
wire [127:0] w0, w1, w2, w3;
wire [31:0] temp;
assign w0 = key_reg[127:96];
assign w1 = key_reg[95:64];
assign w2 = key_reg[63:32];
assign w3 = key_reg[31:0];
assign temp = sub_word(rot_word(w3)) ^ {24'h000000, rcon};
assign next_key = {w0 ^ temp, w1 ^ w0 ^ temp, w2 ^ w1 ^ w0 ^ temp, w3 ^ w2 ^ w1 ^ w0 ^ temp};
// 流水线第2级:寄存器更新
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
key_reg <= 128'h0;
round_cnt <= 4'd0;
round_key <= 128'h0;
key_ready <= 1'b0;
rcon <= 8'h00;
end else if (key_valid) begin
key_reg <= initial_key; // 加载初始密钥
round_cnt <= 4'd1;
rcon <= get_rcon(4'd1);
round_key <= initial_key; // 第0轮密钥直接输出
key_ready <= 1'b1;
end else if (round_cnt <= 4'd10) begin
key_reg <= next_key; // 更新为下一轮密钥
round_key <= key_reg; // 输出当前轮密钥
rcon <= get_rcon(round_cnt + 1'b1);
round_cnt <= round_cnt + 1'b1;
end else begin
key_ready <= 1'b0; // 全部轮密钥生成完毕
end
end
endmodule
流水线并行机制说明
上述模块中,next_key为纯组合逻辑,在时钟上升沿到来前已计算出下一轮密钥。因此每个时钟周期内,key_reg更新与round_key输出同时完成,加密轮模块无需等待密钥扩展,可直接从round_key端口取用当前轮密钥。关键路径被限制在S-box查找与异或链的组合逻辑内,且该路径在下一时钟沿之前有完整周期完成,消除了传统串行方案中“先算密钥再加密”的等待延迟。
仿真验证方法
// 测试平台(testbench)核心逻辑
module tb_key_expand;
reg clk = 0;
reg rst_n = 0;
reg key_valid = 0;
reg [127:0] initial_key = 128'h000102030405060708090a0b0c0d0e0f;
wire [127:0] round_key;
wire key_ready;
key_expand_pipeline uut (
.clk(clk), .rst_n(rst_n), .key_valid(key_valid),
.initial_key(initial_key), .round_key(round_key), .key_ready(key_ready)
);
always #5 clk = ~clk;
initial begin
#10 rst_n = 1;
#10 key_valid = 1;
#10 key_valid = 0;
// 观察round_key在连续11个时钟周期内的输出
// 预期第0轮:000102030405060708090a0b0c0d0e0f
// 第1轮:d6aa74fdd2af72fadaa678f1d6ab76fe
// 第2轮:b692cf0b643dbdf1be9bc5006830b3fe
// ...(后续轮密钥与FIPS-197标准一致)
#200 $finish;
end
endmodule
通过条件:在Vivado或Icarus Verilog中运行仿真,观察round_key输出序列。若第0~10轮密钥与FIPS-197标准测试向量完全一致(首轮为000102030405060708090a0b0c0d0e0f,第1轮为d6aa74fdd2af72fadaa678f1d6ab76fe),且key_ready在11轮内保持高电平,则验证通过。
综合时序优化验证
在Vivado中综合后,查看时序报告。对比未流水线版本,本设计的关键路径延迟应显著降低(因密钥扩展不再与加密轮串行等待)。若目标时钟约束(如100MHz)满足建立时间要求,且无时序违例,即证明优化有效。实际延迟数值取决于FPGA型号与布局布线,需以综合报告为准。