AES算法的Verilog流水线实现(带测试)

发布于:2025-06-24 ⋅ 阅读:(10) ⋅ 点赞:(0)

一、AES的Verilog流水线实现原理

AES(高级加密标准)是一种对称加密算法,广泛应用于信息安全领域。Verilog流水线实现能够显著提高AES加密的吞吐量,使其适合高速数据处理场景。该实现采用128位密钥(AES-128),通过将加密过程分解为多个流水线阶段,每个时钟周期可以处理不同的数据块。

流水线设计的关键在于将AES的10轮加密操作划分为独立的处理阶段。每个加密轮次由四个基本操作组成:字节替换(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(AddRoundKey)。在流水线实现中,这些操作被分配到不同的硬件模块,数据在各模块间流动时可以实现并行处理。

密钥扩展模块采用另一种流水线策略,它预先计算所有轮密钥并存储在寄存器中。这种设计虽然增加了初始延迟,但一旦密钥扩展完成,加密过程可以全速运行,无需等待轮密钥计算。主密钥通过load_mkey信号加载后,模块会在内部生成10个轮密钥。

整个系统采用同步设计,所有操作在时钟上升沿触发。busy信号指示系统状态,防止在密钥扩展或加密过程中加载新数据。这种设计在保证数据安全性的同时,实现了较高的时钟频率和吞吐量,适合FPGA或ASIC实现。

二、Verilog代码解析

1. aes_top模块

aes_top是系统的顶层模块,负责连接密钥扩展和加密模块,并提供统一的外部接口。它包含时钟、复位、主密钥加载、明文输入和密文输出等信号。busy信号由密钥扩展和加密模块的busy信号逻辑或得到,指示系统是否就绪。

该模块实例化了两个主要子模块:key_expand和encrypt。key_expand负责从主密钥生成所有轮密钥,encrypt则执行实际的AES加密操作。round_keys_flatten信号将11个128位轮密钥拼接成1408位宽总线,在模块间传递。

顶层设计采用了清晰的流水线控制策略。当load_mkey有效时加载主密钥,din_valid有效时开始加密过程。dout_valid信号指示输出密文有效,完成了从输入到输出的完整流水线控制。

module aes_top (
    input clk,
    input rst_n,
    
    input [127:0] mkey,
    input load_mkey,

    input [127:0] plaintext,
    input din_valid,

    output [127:0] ciphertext,
    output dout_valid,
    
    output busy
);
    wire [1407:0] round_keys_flatten;
    wire encrypt_busy;
    wire key_expand_busy;

    assign busy = encrypt_busy | key_expand_busy;

    encrypt u_en (
        .clk(clk),
        .rst_n(rst_n),
        .din_valid(din_valid),
        .plaintext(plaintext),
        .ciphertext(ciphertext),
        .dout_valid(dout_valid),
        .busy(encrypt_busy),
        .round_keys_flatten(round_keys_flatten)
    );

    key_expand u_ke (
        .clk(clk),
        .rst_n(rst_n),
        .load_mkey(load_mkey),
        .mkey(mkey),
        .round_keys_flatten(round_keys_flatten),
        .busy(key_expand_busy)
    );
endmodule

2. key_expand模块

key_expand模块实现了AES的密钥扩展算法,将128位主密钥扩展为11个128位轮密钥。模块采用状态机控制,round_ctrl寄存器实现10步扩展过程。每次扩展使用rcon常量进行异或操作,并通过sbox进行非线性变换。

密钥扩展算法基于递推关系,每个新密钥字由前一个密钥字和4个周期前的密钥字计算得到。模块中w0-w3寄存器存储中间状态,rcon_new计算下一轮的轮常量。扩展完成后,所有轮密钥存储在round_keys数组中。

该设计优化了时序性能,通过并行计算四个密钥字(w0_new到w3_new)减少关键路径延迟。busy信号在密钥扩展期间保持有效,防止在扩展过程中加载新主密钥。

module key_expand (
    input clk,
    input rst_n,
    input load_mkey,
    input [127:0] mkey,
    output [1407:0] round_keys_flatten,
    output busy
);
    reg [9:0] round_ctrl;
    reg [7:0] rcon;
    reg [31:0] w0, w1, w2, w3;
    reg [127:0] round_keys[0:10];
    wire [31:0] sbox_out;
    wire [7:0] rcon_new = {rcon[6:0], 1'b0} ^ (rcon[7] ? 8'h1b : 8'h0);
    wire [31:0] w0_new = w0 ^ {sbox_out[31:24] ^ rcon, sbox_out[23:0]};
    wire [31:0] w1_new = w1 ^ w0_new;
    wire [31:0] w2_new = w2 ^ w1_new;
    wire [31:0] w3_new = w3 ^ w2_new;

    wire start_key_expand = load_mkey & ~(|round_ctrl);

    integer i;

    assign round_keys_flatten = {
        round_keys[0], round_keys[1], round_keys[2],
        round_keys[3], round_keys[4], round_keys[5],
        round_keys[6], round_keys[7], round_keys[8],
        round_keys[9], round_keys[10]
    };
    assign busy = load_mkey | (|round_ctrl);

    always @(posedge clk, negedge rst_n) begin
        if (~rst_n) begin
            rcon <= 8'h00;
            {w0, w1, w2, w3} <= 128'h0;
        end else begin
            if (start_key_expand) begin
                {w0, w1, w2, w3} <= mkey;
                rcon <= 8'h01;
            end else if (|round_ctrl) begin
                {w0, w1, w2, w3} <= {w0_new, w1_new, w2_new, w3_new};
                rcon <= rcon_new;
            end
        end
    end

    always @(posedge clk) begin
        if (start_key_expand) begin
            round_keys[0] <= mkey;
        end else if (|round_ctrl) begin
            round_keys[10] <= {w0_new, w1_new, w2_new, w3_new};
            for (i = 10; i > 1; i = i - 1) begin
                round_keys[i-1] <= round_keys[i];
            end
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (~rst_n) begin
            round_ctrl <= 0;
        end else begin
            if (load_mkey) begin
                round_ctrl <= 1;
            end else if (busy) begin
                round_ctrl <= {round_ctrl[8:0], 1'b0};
            end
        end
    end

    sbox sbox1 (.s_in (w3[31:24]), .s_out(sbox_out[7:0]));
    sbox sbox2 (.s_in (w3[7:0]), .s_out(sbox_out[15:8]));
    sbox sbox3 (.s_in (w3[15:8]), .s_out(sbox_out[23:16]));
    sbox sbox4 (.s_in (w3[23:16]), .s_out(sbox_out[31:24]));

endmodule

3. encrypt模块

encrypt模块实现了AES加密的流水线结构。它包含11个状态寄存器(state[0]到state[10]),对应初始密钥加和10轮加密。模块使用round_ctrl移位寄存器控制流水线推进,每个时钟周期数据向下一级移动。

加密过程分为三个阶段:初始轮密钥加、9轮标准加密和最后一轮特殊加密。generate语句实例化了9个encrypt_round模块和1个encrypt_round_last模块,形成完整流水线。round_keys_flatten输入被解包为11个轮密钥。

dout_valid信号由round_ctrl的第10位产生,精确指示加密完成时刻。busy信号在加密过程中保持高电平,防止新数据过早进入流水线。这种设计实现了每个时钟周期处理一个新数据块的吞吐量。

module encrypt (
    input clk,
    input rst_n,
    input din_valid,
    input [127:0] plaintext,
    output [127:0] ciphertext,
    output dout_valid,
    output busy,

    input [1407:0] round_keys_flatten
);
    reg [11:0] round_ctrl;
    reg [127:0] state[0:10];
    wire [127:0] round_out[0:9];
    wire [127:0] round_keys[0:10];

    integer i;
    genvar j;

    assign {
        round_keys[0], round_keys[1], round_keys[2],
        round_keys[3], round_keys[4], round_keys[5],
        round_keys[6], round_keys[7], round_keys[8],
        round_keys[9], round_keys[10]
    } = round_keys_flatten;

    assign ciphertext = state[10];
    assign busy = din_valid | (|round_ctrl);
    assign dout_valid = round_ctrl[10];

    always @(posedge clk, negedge rst_n) begin
        if (~rst_n) begin
            for (i = 0; i < 11; i = i + 1) begin
                state[i] <= 128'h0;
            end
        end else begin
            if (din_valid) begin
                state[0] <= plaintext ^ round_keys[0];
            end
            for (i = 1; i < 11; i = i + 1) begin
                state[i] <= round_out[i-1];
            end
        end
    end

    always @(posedge clk, negedge rst_n) begin
        if (~rst_n) begin
            round_ctrl <= 12'd0;
        end else begin
            round_ctrl <= {round_ctrl[10:0], din_valid};
        end
    end

    generate
        for (j = 0; j < 9; j = j + 1) begin : enr_instances
            encrypt_round u_er (
                .din(state[j]),
                .round_key(round_keys[j+1]),
                .dout(round_out[j])
            );
        end
        encrypt_round_last u_er_last (
            .din(state[9]),
            .round_key(round_keys[10]),
            .dout(round_out[9])
        );
    endgenerate


endmodule

4. encrypt_round模块

encrypt_round实现标准AES加密轮次,包含SubBytes、ShiftRows、MixColumns和AddRoundKey四个步骤。模块使用generate语句实例化16个sbox,并行处理所有字节替换操作。

ShiftRows通过硬连线重新排列字节位置,不消耗逻辑资源。MixColumns使用函数实现,通过gm2和gm3函数计算伽罗瓦域乘法,然后组合成新的列。最后与轮密钥异或完成AddRoundKey操作。

该设计优化了组合逻辑路径,所有步骤在一个时钟周期内完成。模块化设计使得每轮加密可以独立工作,形成高效流水线。

module encrypt_round (
    input [127:0] din,
    input [127:0] round_key,
    output [127:0] dout
);
    wire [127:0] sbox_out, shift_out, mix_out;

    genvar i;
    generate
        for (i = 0; i < 16; i = i + 1) begin : sbox_instances
            sbox u_sbox (
                .s_in (din[i*8+:8]),
                .s_out(sbox_out[i*8+:8])
            );
        end
    endgenerate

    assign shift_out[7:0] = sbox_out[39:32];
    assign shift_out[15:8] = sbox_out[79:72];
    assign shift_out[23:16] = sbox_out[119:112];
    assign shift_out[31:24] = sbox_out[31:24];
    assign shift_out[39:32] = sbox_out[71:64];
    assign shift_out[47:40] = sbox_out[111:104];
    assign shift_out[55:48] = sbox_out[23:16];
    assign shift_out[63:56] = sbox_out[63:56];
    assign shift_out[71:64] = sbox_out[103:96];
    assign shift_out[79:72] = sbox_out[15:8];
    assign shift_out[87:80] = sbox_out[55:48];
    assign shift_out[95:88] = sbox_out[95:88];
    assign shift_out[103:96] = sbox_out[7:0];
    assign shift_out[111:104] = sbox_out[47:40];
    assign shift_out[119:112] = sbox_out[87:80];
    assign shift_out[127:120] = sbox_out[127:120];

    assign mix_out = mixcolumns(shift_out);

    assign dout = mix_out ^ round_key;

    function [7:0] gm2(input [7:0] op);
        begin
            gm2 = {op[6:0], 1'b0} ^ (8'h1b & {8{op[7]}});
        end
    endfunction

    function [7:0] gm3(input [7:0] op);
        begin
            gm3 = gm2(op) ^ op;
        end
    endfunction

    function [31:0] mixw(input [31:0] w);
        reg [7:0] b0, b1, b2, b3;
        reg [7:0] mb0, mb1, mb2, mb3;
        begin
            {b0, b1, b2, b3} = w;

            mb0              = gm2(b0) ^ gm3(b1) ^ b2 ^ b3;
            mb1              = b0 ^ gm2(b1) ^ gm3(b2) ^ b3;
            mb2              = b0 ^ b1 ^ gm2(b2) ^ gm3(b3);
            mb3              = gm3(b0) ^ b1 ^ b2 ^ gm2(b3);

            mixw             = {mb0, mb1, mb2, mb3};
        end
    endfunction

    function [127:0] mixcolumns(input [127:0] data);
        reg [31:0] w0, w1, w2, w3;
        begin
            {w0, w1, w2, w3} = data;
            mixcolumns = {mixw(w0), mixw(w1), mixw(w2), mixw(w3)};
        end
    endfunction

endmodule


module encrypt_round_last (
    input [127:0] din,
    input [127:0] round_key,
    output [127:0] dout
);
    wire [127:0] sbox_out, shift_out, mix_out;

    genvar i;
    generate
        for (i = 0; i < 16; i = i + 1) begin : sbox_instances
            sbox u_sbox (
                .s_in (din[i*8+:8]),
                .s_out(sbox_out[i*8+:8])
            );
        end
    endgenerate

    assign shift_out[7:0] = sbox_out[39:32];
    assign shift_out[15:8] = sbox_out[79:72];
    assign shift_out[23:16] = sbox_out[119:112];
    assign shift_out[31:24] = sbox_out[31:24];
    assign shift_out[39:32] = sbox_out[71:64];
    assign shift_out[47:40] = sbox_out[111:104];
    assign shift_out[55:48] = sbox_out[23:16];
    assign shift_out[63:56] = sbox_out[63:56];
    assign shift_out[71:64] = sbox_out[103:96];
    assign shift_out[79:72] = sbox_out[15:8];
    assign shift_out[87:80] = sbox_out[55:48];
    assign shift_out[95:88] = sbox_out[95:88];
    assign shift_out[103:96] = sbox_out[7:0];
    assign shift_out[111:104] = sbox_out[47:40];
    assign shift_out[119:112] = sbox_out[87:80];
    assign shift_out[127:120] = sbox_out[127:120];

    assign dout = shift_out ^ round_key;
endmodule

5. sbox模块

sbox模块实现AES的字节替换表,使用查找表方式实现非线性变换。模块包含256个8位预计算值,通过输入字节直接寻址获得输出。

module sbox(
	input [7:0] s_in,
	output [7:0] s_out
);
reg [7:0] sbox[0:255];
initial begin
	sbox[000]=8'h63; sbox[001]=8'h7c; sbox[002]=8'h77; sbox[003]=8'h7b; sbox[004]=8'hf2; sbox[005]=8'h6b; sbox[006]=8'h6f; sbox[007]=8'hc5;
	sbox[008]=8'h30; sbox[009]=8'h01; sbox[010]=8'h67; sbox[011]=8'h2b; sbox[012]=8'hfe; sbox[013]=8'hd7; sbox[014]=8'hab; sbox[015]=8'h76;
	sbox[016]=8'hca; sbox[017]=8'h82; sbox[018]=8'hc9; sbox[019]=8'h7d; sbox[020]=8'hfa; sbox[021]=8'h59; sbox[022]=8'h47; sbox[023]=8'hf0;
	sbox[024]=8'had; sbox[025]=8'hd4; sbox[026]=8'ha2; sbox[027]=8'haf; sbox[028]=8'h9c; sbox[029]=8'ha4; sbox[030]=8'h72; sbox[031]=8'hc0;
	sbox[032]=8'hb7; sbox[033]=8'hfd; sbox[034]=8'h93; sbox[035]=8'h26; sbox[036]=8'h36; sbox[037]=8'h3f; sbox[038]=8'hf7; sbox[039]=8'hcc;
	sbox[040]=8'h34; sbox[041]=8'ha5; sbox[042]=8'he5; sbox[043]=8'hf1; sbox[044]=8'h71; sbox[045]=8'hd8; sbox[046]=8'h31; sbox[047]=8'h15;
	sbox[048]=8'h04; sbox[049]=8'hc7; sbox[050]=8'h23; sbox[051]=8'hc3; sbox[052]=8'h18; sbox[053]=8'h96; sbox[054]=8'h05; sbox[055]=8'h9a;
	sbox[056]=8'h07; sbox[057]=8'h12; sbox[058]=8'h80; sbox[059]=8'he2; sbox[060]=8'heb; sbox[061]=8'h27; sbox[062]=8'hb2; sbox[063]=8'h75;
	sbox[064]=8'h09; sbox[065]=8'h83; sbox[066]=8'h2c; sbox[067]=8'h1a; sbox[068]=8'h1b; sbox[069]=8'h6e; sbox[070]=8'h5a; sbox[071]=8'ha0;
	sbox[072]=8'h52; sbox[073]=8'h3b; sbox[074]=8'hd6; sbox[075]=8'hb3; sbox[076]=8'h29; sbox[077]=8'he3; sbox[078]=8'h2f; sbox[079]=8'h84;
	sbox[080]=8'h53; sbox[081]=8'hd1; sbox[082]=8'h00; sbox[083]=8'hed; sbox[084]=8'h20; sbox[085]=8'hfc; sbox[086]=8'hb1; sbox[087]=8'h5b;
	sbox[088]=8'h6a; sbox[089]=8'hcb; sbox[090]=8'hbe; sbox[091]=8'h39; sbox[092]=8'h4a; sbox[093]=8'h4c; sbox[094]=8'h58; sbox[095]=8'hcf;
	sbox[096]=8'hd0; sbox[097]=8'hef; sbox[098]=8'haa; sbox[099]=8'hfb; sbox[100]=8'h43; sbox[101]=8'h4d; sbox[102]=8'h33; sbox[103]=8'h85;
	sbox[104]=8'h45; sbox[105]=8'hf9; sbox[106]=8'h02; sbox[107]=8'h7f; sbox[108]=8'h50; sbox[109]=8'h3c; sbox[110]=8'h9f; sbox[111]=8'ha8;
	sbox[112]=8'h51; sbox[113]=8'ha3; sbox[114]=8'h40; sbox[115]=8'h8f; sbox[116]=8'h92; sbox[117]=8'h9d; sbox[118]=8'h38; sbox[119]=8'hf5;
	sbox[120]=8'hbc; sbox[121]=8'hb6; sbox[122]=8'hda; sbox[123]=8'h21; sbox[124]=8'h10; sbox[125]=8'hff; sbox[126]=8'hf3; sbox[127]=8'hd2;
	sbox[128]=8'hcd; sbox[129]=8'h0c; sbox[130]=8'h13; sbox[131]=8'hec; sbox[132]=8'h5f; sbox[133]=8'h97; sbox[134]=8'h44; sbox[135]=8'h17;
	sbox[136]=8'hc4; sbox[137]=8'ha7; sbox[138]=8'h7e; sbox[139]=8'h3d; sbox[140]=8'h64; sbox[141]=8'h5d; sbox[142]=8'h19; sbox[143]=8'h73;
	sbox[144]=8'h60; sbox[145]=8'h81; sbox[146]=8'h4f; sbox[147]=8'hdc; sbox[148]=8'h22; sbox[149]=8'h2a; sbox[150]=8'h90; sbox[151]=8'h88;
	sbox[152]=8'h46; sbox[153]=8'hee; sbox[154]=8'hb8; sbox[155]=8'h14; sbox[156]=8'hde; sbox[157]=8'h5e; sbox[158]=8'h0b; sbox[159]=8'hdb;
	sbox[160]=8'he0; sbox[161]=8'h32; sbox[162]=8'h3a; sbox[163]=8'h0a; sbox[164]=8'h49; sbox[165]=8'h06; sbox[166]=8'h24; sbox[167]=8'h5c;
	sbox[168]=8'hc2; sbox[169]=8'hd3; sbox[170]=8'hac; sbox[171]=8'h62; sbox[172]=8'h91; sbox[173]=8'h95; sbox[174]=8'he4; sbox[175]=8'h79;
	sbox[176]=8'he7; sbox[177]=8'hc8; sbox[178]=8'h37; sbox[179]=8'h6d; sbox[180]=8'h8d; sbox[181]=8'hd5; sbox[182]=8'h4e; sbox[183]=8'ha9;
	sbox[184]=8'h6c; sbox[185]=8'h56; sbox[186]=8'hf4; sbox[187]=8'hea; sbox[188]=8'h65; sbox[189]=8'h7a; sbox[190]=8'hae; sbox[191]=8'h08;
	sbox[192]=8'hba; sbox[193]=8'h78; sbox[194]=8'h25; sbox[195]=8'h2e; sbox[196]=8'h1c; sbox[197]=8'ha6; sbox[198]=8'hb4; sbox[199]=8'hc6;
	sbox[200]=8'he8; sbox[201]=8'hdd; sbox[202]=8'h74; sbox[203]=8'h1f; sbox[204]=8'h4b; sbox[205]=8'hbd; sbox[206]=8'h8b; sbox[207]=8'h8a;
	sbox[208]=8'h70; sbox[209]=8'h3e; sbox[210]=8'hb5; sbox[211]=8'h66; sbox[212]=8'h48; sbox[213]=8'h03; sbox[214]=8'hf6; sbox[215]=8'h0e;
	sbox[216]=8'h61; sbox[217]=8'h35; sbox[218]=8'h57; sbox[219]=8'hb9; sbox[220]=8'h86; sbox[221]=8'hc1; sbox[222]=8'h1d; sbox[223]=8'h9e;
	sbox[224]=8'he1; sbox[225]=8'hf8; sbox[226]=8'h98; sbox[227]=8'h11; sbox[228]=8'h69; sbox[229]=8'hd9; sbox[230]=8'h8e; sbox[231]=8'h94;
	sbox[232]=8'h9b; sbox[233]=8'h1e; sbox[234]=8'h87; sbox[235]=8'he9; sbox[236]=8'hce; sbox[237]=8'h55; sbox[238]=8'h28; sbox[239]=8'hdf;
	sbox[240]=8'h8c; sbox[241]=8'ha1; sbox[242]=8'h89; sbox[243]=8'h0d; sbox[244]=8'hbf; sbox[245]=8'he6; sbox[246]=8'h42; sbox[247]=8'h68;
	sbox[248]=8'h41; sbox[249]=8'h99; sbox[250]=8'h2d; sbox[251]=8'h0f; sbox[252]=8'hb0; sbox[253]=8'h54; sbox[254]=8'hbb; sbox[255]=8'h16;
end
 
assign s_out=sbox[s_in];
 
endmodule

三、实验结果

使用iverilog进行快速功能验证,测试了10组明文/密文对,testbench和测试结果如下。所有测试用例均通过,实际输出与预期密文完全一致。测试平台自动比较结果并显示通过/失败信息,验证了设计的正确性。VCD波形文件被成功生成,便于后续分析。

`timescale 1ns/1ps

module aes_top_tb;
    reg clk=0;
    reg rst_n=0;
    
    reg [127:0] mkey=0;
    reg load_mkey=0;

    reg [127:0] plaintext=0;
    reg din_valid=0;

    wire [127:0] ciphertext;
    wire dout_valid;
    wire busy;

    aes_top uut (
        .clk(clk),
        .rst_n(rst_n),
        .mkey(mkey),
        .load_mkey(load_mkey),
        .plaintext(plaintext),
        .din_valid(din_valid),
        .ciphertext(ciphertext),
        .dout_valid(dout_valid),
        .busy(busy)
    );

    always #5 clk = ~clk;

    reg [127:0] test_plaintexts [0:9];
    reg [127:0] expected_ciphertexts [0:9];

    initial begin
        test_plaintexts[0]=128'h00112233445566778899aabbccddeeff;
        test_plaintexts[1]=128'h74c78ff3d66dbf57133ad70f3783632e;
        test_plaintexts[2]=128'h274c7ca8660c45692ae89ad0ccb181ba;
        test_plaintexts[3]=128'h6d996b1ee433d25ec82ae8e525853ef7;
        test_plaintexts[4]=128'h53330c09f3b978bfb6f124ef34329292;
        test_plaintexts[5]=128'h720f5ec1eafcb180549b5dd35aaa4311;
        test_plaintexts[6]=128'hf7cfe13517d5a56ee8390ab607bb1025;
        test_plaintexts[7]=128'h7074fa1315798698fee73b1beb30ab55;
        test_plaintexts[8]=128'h5e6030ea185d0ea90e1a81a84b2f5651;
        test_plaintexts[9]=128'h944375ea4102920901f920a09a86efa7;

        expected_ciphertexts[0]=128'h69c4e0d86a7b0430d8cdb78070b4c55a;
        expected_ciphertexts[1]=128'heb7db34352d001fe483bddb27e9349a1;
        expected_ciphertexts[2]=128'h67d455bea9e118bd8425eaf27bc08933;
        expected_ciphertexts[3]=128'h5fe2c1898df6a83b9b061c589357f587;
        expected_ciphertexts[4]=128'h965c2dba77ff86a316199702c7c36728;
        expected_ciphertexts[5]=128'h5edcf52367a8f289ff6fc2a41d2752a9;
        expected_ciphertexts[6]=128'h22f0eaf54a178cf157514dcf83673862;
        expected_ciphertexts[7]=128'h6a1ce927be8ea92bcf185f4370c29087;
        expected_ciphertexts[8]=128'h2f1043780796ac3b4332e5e09460f327;
        expected_ciphertexts[9]=128'h4a5a4421892df67cd9b8af80c0b8f3b6;
    end

    integer i = 0;

    initial begin
        #15 rst_n = 1;
        mkey = 128'h000102030405060708090a0b0c0d0e0f;
        load_mkey = 1;
        @(negedge clk);
        load_mkey = 0;

        wait(busy == 0);
        @(negedge clk);
        #20 plaintext=test_plaintexts[0]; din_valid = 1;
        #10 din_valid = 0;

        #20 plaintext = test_plaintexts[1]; din_valid = 1;
        #10 plaintext = test_plaintexts[2];
        #10 plaintext = test_plaintexts[3];
        #10 plaintext = test_plaintexts[4];
        #10 din_valid = 0;

        #30 plaintext = test_plaintexts[5]; din_valid = 1;
        #10 plaintext = test_plaintexts[6];
        #10 plaintext = test_plaintexts[7];
        #10 plaintext = test_plaintexts[8];
        #10 plaintext = test_plaintexts[9];
        #10 din_valid = 0;

        wait(busy == 0);
        #100 $finish;
    end

    always @(posedge clk) begin
        if (dout_valid) begin
            if (ciphertext === expected_ciphertexts[i]) begin
                $display("Test %0d: Passed, Expected %h, Actual %h", i, expected_ciphertexts[i], ciphertext);
            end else begin
                $display("Test %0d: Failed, Expected %h, Actual %h", i, expected_ciphertexts[i], ciphertext);
            end
            i = i + 1;
        end
    end

    initial begin
        $dumpfile("aes_top.vcd");
        $dumpvars(0, aes_top_tb);
    end
endmodule

在gtkwave和Modelsim中观察仿真波形,可以清晰看到流水线的工作过程。当din_valid有效时,明文进入流水线,经过11个周期后dout_valid变高,输出有效密文。busy信号准确反映了系统状态,密钥扩展和加密过程没有重叠时的控制信号行为符合预期。

用Vivado(XC7A35T-1CSG324C)进行综合,结果如下:

四、总结

AES算法是一种广泛使用的对称加密标准,其Verilog流水线实现通过将加密过程分解为多级处理,显著提高了数据吞吐量。该设计采用128位密钥,包含密钥扩展和加密两大模块,通过流水线结构实现每个时钟周期处理一个数据块。密钥扩展模块预先计算所有轮密钥,加密模块则分为初始轮加、9轮标准加密和最终轮加密,形成11级流水线。实验验证表明,该设计功能正确,所有测试用例均通过验证。每周期128位的吞吐量使其适合高速加密场景,而模块化设计便于在不同平台移植和优化,为安全通信提供了高效的硬件解决方案。


网站公告

今日签到

点亮在社区的每一天
去签到