阶段二哈希与认证 — 在压缩函数基础上,加入消息填充和多块处理,构建完整的 SHA-256 哈希引擎。
消息填充规则:追加 bit '1',然后填充零直到长度 ≡ 448 mod 512,最后追加 64 位原始消息长度。
// sha256_pad.v - SHA-256 消息填充模块
module sha256_pad (
input wire clk,
input wire rst_n,
input wire msg_valid, // 消息字有效
input wire [31:0] msg_word, // 32位消息字
input wire msg_last, // 最后一个字
input wire [5:0] msg_len_mod, // 消息长度 mod 64 (字数)
output reg [511:0] block_out, // 512位填充后的块
output reg block_valid, // 块有效信号
output reg pad_done // 填充完成
);
reg [31:0] block_buf [0:15]; // 16 个 32 位字
reg [3:0] word_cnt;
reg storing;
integer j;
initial begin
for (j = 0; j < 16; j = j + 1) block_buf[j] = 0;
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
block_valid <= 0; pad_done <= 0;
word_cnt <= 0; storing <= 0;
for (j = 0; j < 16; j = j + 1) block_buf[j] <= 0;
end else begin
block_valid <= 0;
if (msg_valid && !pad_done) begin
block_buf[word_cnt] <= msg_word;
word_cnt <= word_cnt + 1;
if (msg_last) begin
// 追加 0x80000000
block_buf[word_cnt + 1] <= 32'h80000000;
// 如果剩余空间不足放长度,需要两个块
if (word_cnt >= 14) begin
// 第一个块剩余填零
storing <= 1;
end else begin
// 填零直到第14个字,第15-16字放长度
block_buf[15] <= {msg_len_mod, 26'h0}; // 简化
block_valid <= 1;
pad_done <= 1;
end
end
end
end
end
// 输出组装
always @(*) begin
block_out = {block_buf[0],block_buf[1],block_buf[2],block_buf[3],
block_buf[4],block_buf[5],block_buf[6],block_buf[7],
block_buf[8],block_buf[9],block_buf[10],block_buf[11],
block_buf[12],block_buf[13],block_buf[14],block_buf[15]};
end
endmodule
// sha256_engine.v - SHA-256 完整引擎
module sha256_engine (
input wire clk,
input wire rst_n,
input wire start,
input wire [511:0] block, // 填充后的512位消息块
input wire block_valid,
input wire last_block,
output reg [255:0] digest,
output reg digest_valid
);
// SHA-256 初始哈希值
localparam [31:0] H_INIT [0:7];
// Verilator 不支持 localparam 数组初始化,用 reg initial
reg [31:0] h_init [0:7];
initial begin
h_init[0]=32'h6a09e667; h_init[1]=32'hbb67ae85;
h_init[2]=32'h3c6ef372; h_init[3]=32'ha54ff53a;
h_init[4]=32'h510e527f; h_init[5]=32'h9b05688c;
h_init[6]=32'h1f83d9ab; h_init[7]=32'h5be0cd19;
end
// 轮常量 K[0..63]
reg [31:0] K [0:63];
initial begin
K[0]=32'h428a2f98; K[1]=32'h71374491; K[2]=32'hb5c0fbcf; K[3]=32'he9b5dba5;
K[4]=32'h3956c25b; K[5]=32'h59f111f1; K[6]=32'h923f82a4; K[7]=32'hab1c5ed5;
K[8]=32'hd807aa98; K[9]=32'h12835b01; K[10]=32'h243185be; K[11]=32'h550c7dc3;
K[12]=32'h72be5d74; K[13]=32'h80deb1fe; K[14]=32'h9bdc06a7; K[15]=32'hc19bf174;
K[16]=32'he49b69c1; K[17]=32'hefbe4786; K[18]=32'h0fc19dc6; K[19]=32'h240ca1cc;
K[20]=32'h2de92c6f; K[21]=32'h4a7484aa; K[22]=32'h5cb0a9dc; K[23]=32'h76f988da;
K[24]=32'h983e5152; K[25]=32'ha831c66d; K[26]=32'hb00327c8; K[27]=32'hbf597fc7;
K[28]=32'hc6e00bf3; K[29]=32'hd5a79147; K[30]=32'h06ca6351; K[31]=32'h14292967;
K[32]=32'h27b70a85; K[33]=32'h2e1b2138; K[34]=32'h4d2c6dfc; K[35]=32'h53380d13;
K[36]=32'h650a7354; K[37]=32'h766a0abb; K[38]=32'h81c2c92e; K[39]=32'h92722c85;
K[40]=32'ha2bfe8a1; K[41]=32'ha81a664b; K[42]=32'hc24b8b70; K[43]=32'hc76c51a3;
K[44]=32'hd192e819; K[45]=32'hd6990624; K[46]=32'hf40e3585; K[47]=32'h106aa070;
K[48]=32'h19a4c116; K[49]=32'h1e376c08; K[50]=32'h2748774c; K[51]=32'h34b0bcb5;
K[52]=32'h391c0cb3; K[53]=32'h4ed8aa4a; K[54]=32'h5b9cca4f; K[55]=32'h682e6ff3;
K[56]=32'h748f82ee; K[57]=32'h78a5636f; K[58]=32'h84c87814; K[59]=32'h8cc70208;
K[60]=32'h90befffa; K[61]=32'ha4506ceb; K[62]=32'hbef9a3f7; K[63]=32'hc67178f2;
end
reg [31:0] a, b, c, d, e, f, g, h;
reg [31:0] h0, h1, h2, h3, h4, h5, h6, h7; // 中间哈希
reg [31:0] W [0:63];
reg [5:0] rnd;
reg active, first_block;
integer i;
function [31:0] rotr; input [31:0] x; input [4:0] n;
rotr = (x >> n) | (x << (32 - n));
endfunction
wire [31:0] sig0w = rotr(W[rnd-2],7) ^ rotr(W[rnd-2],18) ^ (W[rnd-2]>>3);
wire [31:0] sig1w = rotr(W[rnd-15],17) ^ rotr(W[rnd-15],19) ^ (W[rnd-15]>>10);
wire [31:0] bs0 = rotr(a,2) ^ rotr(a,13) ^ rotr(a,22);
wire [31:0] bs1 = rotr(e,6) ^ rotr(e,11) ^ rotr(e,25);
wire [31:0] ch = (e & f) ^ (~e & g);
wire [31:0] maj = (a & b) ^ (a & c) ^ (b & c);
wire [31:0] t1 = h + bs1 + ch + K[rnd] + W[rnd];
wire [31:0] t2 = bs0 + maj;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
active <= 0; digest_valid <= 0;
{h0,h1,h2,h3,h4,h5,h6,h7} <= {h_init[0],h_init[1],h_init[2],h_init[3],
h_init[4],h_init[5],h_init[6],h_init[7]};
end else if (start) begin
{h0,h1,h2,h3,h4,h5,h6,h7} <= {h_init[0],h_init[1],h_init[2],h_init[3],
h_init[4],h_init[5],h_init[6],h_init[7]};
first_block <= 1;
end else if (block_valid && !active) begin
a <= h0; b <= h1; c <= h2; d <= h3;
e <= h4; f <= h5; g <= h6; h <= h7;
for (i = 0; i < 16; i = i + 1)
W[i] <= block[i*32+31 -: 32];
rnd <= 0; active <= 1; digest_valid <= 0;
end else if (active) begin
if (rnd < 64) begin
if (rnd >= 16) W[rnd] <= sig1w + W[rnd-7] + sig0w + W[rnd-16];
h <= g; g <= f; f <= e;
e <= d + t1; d <= c; c <= b; b <= a;
a <= t1 + t2;
rnd <= rnd + 1;
end else begin
h0 <= h0 + a; h1 <= h1 + b; h2 <= h2 + c; h3 <= h3 + d;
h4 <= h4 + e; h5 <= h5 + f; h6 <= h6 + g; h7 <= h7 + h;
active <= 0;
if (last_block) begin
digest <= {h0+a, h1+b, h2+c, h3+d, h4+e, h5+f, h6+g, h7+h};
digest_valid <= 1;
end
end
end
end
endmodule
// SHA-256("abc") = ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad
module sha256_engine_tb;
reg clk, rst_n, start, block_valid, last_block;
reg [511:0] block;
wire [255:0] digest;
wire digest_valid;
sha256_engine uut (.*);
always #5 clk = ~clk;
initial begin
clk=0; rst_n=0; start=0; block_valid=0; last_block=0;
#20 rst_n=1; start=1; #10; start=0;
// "abc" 填充后:61626380 00000000 ... 00000018
block = {32'h61626380, 32'h0, 32'h0, 32'h0,
32'h0, 32'h0, 32'h0, 32'h0,
32'h0, 32'h0, 32'h0, 32'h0,
32'h0, 32'h0, 32'h0, 32'h00000018};
block_valid = 1; last_block = 1;
#10; block_valid = 0;
wait(digest_valid);
$display("SHA-256(abc) = %064h", digest);
$display("Expected = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
$finish;
end
endmodule
1. 验证 SHA-256("") = e3b0c44298fc1c14... 和 SHA-256("abc") 的正确性。
2. 实现一个支持流式输入的 SHA-256:每周期接收 32 位消息字,自动处理填充。
3. 计算双块消息的 SHA-256 哈希(消息长度 > 448 位)。
4. 优化:将 64 轮压缩改为展开 4 轮,减少控制开销,分析面积和吞吐量的变化。
你已构建完整的 SHA-256 哈希引擎,从消息填充到多块迭代压缩。SHA-256 是互联网安全的基石之一!
获得徽章:🔒 SHA256_ENGINEER
推荐使用以下工具链进行课程实践:
# 安装 Verilator
sudo apt install verilator
# 安装 Icarus Verilog(可选)
sudo apt install iverilog
# 安装 GTKWave(波形查看器)
sudo apt install gtkwave
# 验证安装
verilator --lint-only --version
iverilog -V
密码学硬件实现的关键性能指标:
这些指标之间通常存在 trade-off,设计时需根据应用场景权衡。
本课涉及的核心概念和技术关系:
Verilog 仿真调试的常用方法:
// 调试示例
initial begin
$dumpfile("sim.vcd");
$dumpvars(0, uut);
end
// 断言验证
assert property (@(posedge clk) valid |-> data !== 'x)
else $error("Invalid data when valid!");
# 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 偏重面积和能效,服务器偏重吞吐量。