SIMON64/128算法Verilog流水线实现(附Python实现)

一、SIMON算法简介

SIMON算法是由美国国家安全局设计的一种轻量级分组密码算法,以其简洁高效的特点在资源受限环境中得到广泛应用。论文下载地址:The SIMON and SPECK lightweight block ciphers。该算法采用Feistel结构,具有硬件实现面积小、功耗低等优势。SIMON64/128是SIMON算法家族中的一个具体配置,其中64表示分组长度,128表示密钥长度。整个加密过程包含44轮迭代操作,每轮都包含特定的轮函数计算和轮密钥加操作。

SIMON算法的核心在于其轮函数设计,通过循环移位、按位与和异或运算的组合实现非线性变换。这种设计既保证了密码强度,又使得硬件实现极为高效。轮函数中包含了左循环移位、按位与运算和异或运算,这些操作在硬件层面都可以用极少的逻辑资源实现。

二、流水线实现

本设计采用Verilog硬件描述语言实现了SIMON64/128算法的四级流水线结构。整个系统由三个主要模块构成:顶层控制模块、密钥扩展模块和轮函数计算模块。

在顶层simon模块中,通过精心设计的流水线架构实现了高效的数据处理。系统采用四级流水线,每级处理11轮加密操作,四个simon_round模块并行工作,显著提高了吞吐量。状态寄存器数组state[0:4]构成了流水线的核心,负责在时钟边沿传递中间计算结果。这种设计使得每个时钟周期都能开始一个新的加密操作,极大提升了系统性能。

密钥扩展模块key_shedule采用序列化设计,通过40个时钟周期完成全部44个轮密钥的生成。该模块利用常数序列Z3和特定的密钥更新函数,从初始128位主密钥派生出所有轮密钥。密钥扩展过程中采用了循环移位和异或运算的组合,确保生成的轮密钥满足密码学安全要求。

轮函数模块simon_round实现了11轮连续的加密操作。每个轮函数包含标准的SIMON轮操作:首先对左半部分进行循环移位和按位与操作,然后将结果与右半部分和轮密钥进行异或。通过11级组合逻辑的级联,该模块在一个时钟周期内完成11轮变换,体现了深度流水线设计的优势。

控制逻辑方面,系统通过ks_busy和encrypt_busy信号协调密钥扩展和加密过程。din_vld_delay寄存器链实现了精确的输出有效性控制,确保只有在完整加密完成后才标记输出有效。这种设计保证了数据处理的正确性和时序的精确性。

cpp 复制代码
module simon (
    input clk,
    input rst_n,
    input encrypt,
    input load_key,
    input [63:0] plaintext,
    input [127:0] key,
    output [63:0] ciphertext,
    output reg dout_vld,
    output simon_busy
);
wire ks_busy;
wire encrypt_busy;
wire [32*44-1:0] rkey;
wire [31:0] rkey_part[0:43];
wire [63:0] round_out[0:3];

reg [63:0] state[0:4];
reg [3:0] din_vld_delay;

assign ciphertext = state[4];
assign encrypt_busy = encrypt | (|din_vld_delay);
assign simon_busy = encrypt_busy | ks_busy;

always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        state[0] <= 64'd0;
        state[1] <= 64'd0;
        state[2] <= 64'd0;
        state[3] <= 64'd0;
        state[4] <= 64'd0;
    end else begin
        state[1] <= round_out[0];
        state[2] <= round_out[1];
        state[3] <= round_out[2];
        state[4] <= round_out[3];
        if(~ks_busy&encrypt)state[0] <= plaintext;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        din_vld_delay <= 4'd0;
        dout_vld <= 1'b0;
    end else if (~ks_busy) begin
        din_vld_delay <= {encrypt, din_vld_delay[3:1]};
        dout_vld <= din_vld_delay[0];
    end
end

genvar i;
generate
    for (i = 0; i < 44; i = i + 1) begin : assign_rkey
        assign rkey_part[i] = rkey[32*(44-i)-1 : 32*(43-i)];
    end
endgenerate

key_shedule u_ks(
    .clk(clk),
    .rst_n(rst_n),
    .load_key(load_key),
    .key(key),
    .rkey(rkey),
    .ks_busy(ks_busy)
);

simon_round u_r1to11 (
    .din(state[0]),
    .key1(rkey_part[0]),
    .key2(rkey_part[1]),
    .key3(rkey_part[2]),
    .key4(rkey_part[3]),
    .key5(rkey_part[4]),
    .key6(rkey_part[5]),
    .key7(rkey_part[6]),
    .key8(rkey_part[7]),
    .key9(rkey_part[8]),
    .key10(rkey_part[9]),
    .key11(rkey_part[10]),
    .dout(round_out[0])
);
simon_round u_r12to22 (
    .din(state[1]),
    .key1(rkey_part[11]),
    .key2(rkey_part[12]),
    .key3(rkey_part[13]),
    .key4(rkey_part[14]),
    .key5(rkey_part[15]),
    .key6(rkey_part[16]),
    .key7(rkey_part[17]),
    .key8(rkey_part[18]),
    .key9(rkey_part[19]),
    .key10(rkey_part[20]),
    .key11(rkey_part[21]),
    .dout(round_out[1])
);
simon_round u_r23to33 (
    .din(state[2]),
    .key1(rkey_part[22]),
    .key2(rkey_part[23]),
    .key3(rkey_part[24]),
    .key4(rkey_part[25]),
    .key5(rkey_part[26]),
    .key6(rkey_part[27]),
    .key7(rkey_part[28]),
    .key8(rkey_part[29]),
    .key9(rkey_part[30]),
    .key10(rkey_part[31]),
    .key11(rkey_part[32]),
    .dout(round_out[2])
);
simon_round u_r34to44 (
    .din(state[3]),
    .key1(rkey_part[33]),
    .key2(rkey_part[34]),
    .key3(rkey_part[35]),
    .key4(rkey_part[36]),
    .key5(rkey_part[37]),
    .key6(rkey_part[38]),
    .key7(rkey_part[39]),
    .key8(rkey_part[40]),
    .key9(rkey_part[41]),
    .key10(rkey_part[42]),
    .key11(rkey_part[43]),
    .dout(round_out[3])
);
endmodule

module simon_round (
    input [63:0] din,
    input [31:0] key1,
    input [31:0] key2,
    input [31:0] key3,
    input [31:0] key4,
    input [31:0] key5,
    input [31:0] key6,
    input [31:0] key7,
    input [31:0] key8,
    input [31:0] key9,
    input [31:0] key10,
    input [31:0] key11,
    output [63:0] dout
);
wire [31:0] x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11;
wire [31:0] y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11;
wire [31:0] f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11;

assign x1 = din[63:32], y1=din[31:0];
assign f1=({x1[30:0],x1[31]}&{x1[23:0],x1[31:24]})^{x1[29:0],x1[31:30]};
assign x2 = y1 ^ f1 ^ key1, y2 = x1;
assign f2=({x2[30:0],x2[31]}&{x2[23:0],x2[31:24]})^{x2[29:0],x2[31:30]};
assign x3 = y2 ^ f2 ^ key2, y3 = x2;
assign f3=({x3[30:0],x3[31]}&{x3[23:0],x3[31:24]})^{x3[29:0],x3[31:30]};
assign x4 = y3 ^ f3 ^ key3, y4 = x3;
assign f4=({x4[30:0],x4[31]}&{x4[23:0],x4[31:24]})^{x4[29:0],x4[31:30]};
assign x5 = y4 ^ f4 ^ key4, y5 = x4;
assign f5=({x5[30:0],x5[31]}&{x5[23:0],x5[31:24]})^{x5[29:0],x5[31:30]};
assign x6 = y5 ^ f5 ^ key5, y6 = x5;
assign f6=({x6[30:0],x6[31]}&{x6[23:0],x6[31:24]})^{x6[29:0],x6[31:30]};
assign x7 = y6 ^ f6 ^ key6, y7 = x6;
assign f7=({x7[30:0],x7[31]}&{x7[23:0],x7[31:24]})^{x7[29:0],x7[31:30]};
assign x8 = y7 ^ f7 ^ key7, y8 = x7;
assign f8=({x8[30:0],x8[31]}&{x8[23:0],x8[31:24]})^{x8[29:0],x8[31:30]};
assign x9 = y8 ^ f8 ^ key8, y9 = x8;
assign f9=({x9[30:0],x9[31]}&{x9[23:0],x9[31:24]})^{x9[29:0],x9[31:30]};
assign x10 = y9 ^ f9 ^ key9, y10 = x9;
assign f10=({x10[30:0],x10[31]}&{x10[23:0],x10[31:24]})^{x10[29:0],x10[31:30]};
assign x11 = y10 ^ f10 ^ key10, y11 = x10;
assign f11=({x11[30:0],x11[31]}&{x11[23:0],x11[31:24]})^{x11[29:0],x11[31:30]};
assign dout = {y11 ^ f11 ^ key11, x11};

endmodule

module key_shedule (
    input clk,
    input rst_n,
    input load_key,
    input [127:0] key,
    output [32*44-1:0] rkey,
    output ks_busy
);
localparam [0:39] Z3= 40'b1101101110101100011001011110000001001000;

integer i;
reg busy;
reg [31:0] rkey_r[0:43];
reg [7:0] key_counter;
wire [31:0] key_tmp1, key_tmp2;

assign rkey={rkey_r[0], rkey_r[1], rkey_r[2], rkey_r[3], rkey_r[4], rkey_r[5], rkey_r[6], rkey_r[7],
               rkey_r[8], rkey_r[9], rkey_r[10], rkey_r[11], rkey_r[12], rkey_r[13], rkey_r[14], rkey_r[15],
               rkey_r[16], rkey_r[17], rkey_r[18], rkey_r[19], rkey_r[20], rkey_r[21], rkey_r[22], rkey_r[23],
               rkey_r[24], rkey_r[25], rkey_r[26], rkey_r[27], rkey_r[28], rkey_r[29], rkey_r[30], rkey_r[31],
               rkey_r[32], rkey_r[33], rkey_r[34], rkey_r[35], rkey_r[36], rkey_r[37], rkey_r[38], rkey_r[39],
               rkey_r[40], rkey_r[41], rkey_r[42], rkey_r[43]};
assign key_tmp1 = {rkey_r[43][2:0], rkey_r[43][31:3]}^rkey_r[41];
assign key_tmp2 = rkey_r[40]^key_tmp1^{key_tmp1[0],key_tmp1[31:1]}^32'hfffffffc;
assign ks_busy = busy|load_key;

always @(posedge clk, negedge rst_n) begin
if(!rst_n)begin
    key_counter<=8'd0;
    busy<=1'b0;
    for(i=0;i<44;i=i+1)begin
        rkey_r[i]<=32'd0;
    end
end else begin
    if(load_key & ~busy) begin
        busy<=1'b1;
        rkey_r[40]<=key[127:96];
        rkey_r[41]<=key[95:64];
        rkey_r[42]<=key[63:32];
        rkey_r[43]<=key[31:0];
    end else if(busy) begin
        key_counter<=key_counter+8'd1;
        for(i=0;i<43;i=i+1)begin
            rkey_r[i]<=rkey_r[i+1];
        end
        rkey_r[43]<=key_tmp2^Z3[key_counter];
        if(key_counter==8'd39) begin
            busy<=1'b0;
            key_counter<=8'd0;
        end
    end
end
end

endmodule

三、仿真与总结

我们使用下面的testbech在modelsim上进行仿真:

cpp 复制代码
module tb;
    reg clk;
    reg rst;
    reg encrypt,load_key;
    reg [63:0] plaintext;
    reg [127:0] key;

    wire [63:0] ciphertext;
    wire dout_vld,busy;
	
	simon u_simon(
		.clk(clk), 
        .rst_n(rst),
		.encrypt(encrypt),
		.load_key(load_key),
		.plaintext(plaintext), 
		.key(key), 
		.ciphertext(ciphertext),
		.dout_vld(dout_vld),
		.simon_busy(busy)
	);

    initial begin
        clk = 0;
        rst = 0;
        encrypt=0;
        load_key=0;
        plaintext = 64'h0;
        key = 128'h030201000b0a0908131211101b1a1918;
		
        #20;
        rst = 1;
		
        #20;
        load_key = 1;
		#10;
		load_key = 0;
		
        #10;
        wait(busy==0);
        #25;

        #10;
        encrypt = 1;
		plaintext = 64'h656b696c20646e75;
		#10;
		encrypt=0;
		
        #20;
		encrypt = 1;
        plaintext = 64'h0;
        #10;
        encrypt = 0;
		
		#10;
		encrypt = 1;
        plaintext = 64'hffffffffffffffff;
        #10;
        encrypt = 0;
		
    end
	
    always @(negedge dout_vld) begin
        $display("ciphertext = %h",ciphertext);
    end

    always #5 clk = ~clk;

endmodule

代码中使用了官方测试向量:

modelsim仿真结果如下,可以看到结果与预期完全一致:

该SIMON64/128流水线实现展示了现代密码算法硬件优化的典型方法。通过四级流水线架构,系统在面积和速度之间取得了良好平衡,既保持了较高的吞吐率,又控制了硬件资源消耗。密钥扩展与加密操作的并行执行进一步提升了整体效率。

深度组合逻辑的运用使得单个模块能够处理多轮加密,减少了流水线级数,降低了控制复杂度。精心设计的时序控制机制确保了数据在流水线中的正确流动,避免了资源冲突和数据 hazards。

这种实现方式特别适合需要高性能加密的应用场景,如网络安全设备、高速通信系统等。同时,模块化的设计也为进一步优化和配置变更提供了便利,体现了硬件密码实现领域的最佳实践。

附件 Python实现

为了方便理解和对比,最后同时附上Python实现:

python 复制代码
def RLn(x, n):
    t1 = (x << n) & 0xffffffff
    t2 = (x >> (32 - n)) & 0xffffffff
    return t1 | t2


def RRn(x, n):
    t1 = (x >> n) & 0xffffffff
    t2 = (x << (32 - n)) & 0xffffffff
    return t1 | t2


def key_schedule(key):
    z3 = [1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1]
    rkey = [0] * 44
    for i in range(4):
        rkey[i] = key[i]
    for i in range(4, 44):
        tmp1 = RRn(rkey[i - 1], 3) ^ rkey[i - 3]
        tmp2 = tmp1 ^ RRn(tmp1, 1)
        rkey[i] = rkey[i - 4] ^ tmp2 ^ z3[i - 4] ^ 0xfffffffc
        print(f"key{i}: {rkey[i]:08x}")
    return rkey


def encrypt(plain, rkey):
    x, y = plain[0], plain[1]
    for i in range(44):
        tmp = x
        x = y ^ (RLn(x, 1) & RLn(x, 8)) ^ RLn(x, 2) ^ rkey[i]
        y = tmp
        print(f"encrypt{i}: {x:08x} {y:08x}")
    cipher = [x, y]
    return cipher


if __name__ == '__main__':
    plain = [0x656b696c, 0x20646e75]
    key = [0x03020100, 0x0b0a0908, 0x13121110, 0x1b1a1918]
    rkey = key_schedule(key)
    cipher = encrypt(plain, rkey)
    print(f"cipher: {cipher[0]:08x} {cipher[1]:08x}")
相关推荐
轮到我狗叫了2 小时前
力扣.84柱状图中最大矩形 力扣.134加油站牛客.abb(hard 动态规划+哈希表)牛客.哈夫曼编码
算法·leetcode·职场和发展
丛雨要玩游戏2 小时前
字符函数和字符串函数
c语言·开发语言·算法
Shang180989357262 小时前
T41LQ 一款高性能、低功耗的系统级芯片(SoC) 适用于各种AIoT应用智能安防、智能家居方案优选T41L
人工智能·驱动开发·嵌入式硬件·fpga开发·信息与通信·信号处理·t41lq
八个程序员3 小时前
自定义函数(C++)
开发语言·c++·算法
ad钙奶长高高3 小时前
【C语言】初始C语言
c语言·开发语言·算法
BreezeJuvenile3 小时前
外设模块学习(8)——HC-SR04超声波模块(STM32)
stm32·单片机·嵌入式硬件·学习·超声波测距模块·hc-sr04
罗西的思考3 小时前
【Agent】 ACE(Agentic Context Engineering)源码阅读笔记---(3)关键创新
人工智能·算法
Python图像识别4 小时前
75_基于深度学习的咖啡叶片病害检测系统(yolo11、yolov8、yolov5+UI界面+Python项目源码+模型+标注好的数据集)
python·深度学习·yolo
闲人编程4 小时前
Python游戏开发入门:Pygame实战
开发语言·python·游戏·pygame·毕设·codecapsule