阶段二哈希与认证 — SHA-256 是最广泛使用的密码学哈希函数,其核心是压缩函数。本课从压缩函数入手,理解 SHA-256 的数学原理和硬件映射。
SHA-256 将任意长度的消息映射为 256 位(32 字节)的摘要,满足:
压缩函数接受 256 位哈希状态和 512 位消息块,输出新的 256 位状态:
内部有 8 个 32 位工作寄存器 a, b, c, d, e, f, g, h,迭代 64 轮:
将 16 个 32 位消息字扩展为 64 个字:
其中:
其中:
// sha256_compress.v - SHA-256 压缩函数核心
module sha256_compress (
input wire clk,
input wire rst_n,
input wire start,
input wire [255:0] hash_in, // 当前哈希状态
input wire [511:0] block_in, // 512位消息块
output reg [255:0] hash_out, // 新的哈希状态
output reg valid
);
// SHA-256 初始哈希常量
localparam [31:0] H0 = 32'h6a09e667, H1 = 32'hbb67ae85;
localparam [31:0] H2 = 32'h3c6ef372, H3 = 32'ha54ff53a;
localparam [31:0] H4 = 32'h510e527f, H5 = 32'h9b05688c;
localparam [31:0] H6 = 32'h1f83d9ab, H7 = 32'h5be0cd19;
// 64 个轮常量 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 [5:0] round;
reg running;
// 消息调度
reg [31:0] W [0:63];
integer i;
// 辅助函数
function [31:0] rotr;
input [31:0] x;
input [4:0] n;
rotr = (x >> n) | (x << (32 - n));
endfunction
function [31:0] shr;
input [31:0] x;
input [4:0] n;
shr = x >> n;
endfunction
wire [31:0] sigma0 = rotr(W[round-2], 7) ^ rotr(W[round-2], 18) ^ shr(W[round-2], 3);
wire [31:0] sigma1 = rotr(W[round-15],17) ^ rotr(W[round-15],19) ^ shr(W[round-15],10);
wire [31:0] big_s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
wire [31:0] big_s1 = 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 + big_s1 + ch + K[round] + W[round];
wire [31:0] t2 = big_s0 + maj;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
running <= 0; round <= 0; valid <= 0;
hash_out <= 0;
end else if (start && !running) begin
// 初始化
a <= hash_in[255:224]; b <= hash_in[223:192];
c <= hash_in[191:160]; d <= hash_in[159:128];
e <= hash_in[127:96]; f <= hash_in[95:64];
g <= hash_in[63:32]; h <= hash_in[31:0];
// 加载消息字
for (i = 0; i < 16; i = i + 1)
W[i] <= block_in[511 - i*32 -: 32];
round <= 0; running <= 1; valid <= 0;
end else if (running) begin
if (round < 64) begin
// 消息调度扩展
if (round >= 16)
W[round] <= sigma1 + W[round-7] + sigma0 + W[round-16];
// 压缩
h <= g; g <= f; f <= e;
e <= d + t1; d <= c; c <= b; b <= a;
a <= t1 + t2;
round <= round + 1;
end else begin
hash_out <= {a+hash_in[255:224], b+hash_in[223:192],
c+hash_in[191:160], d+hash_in[159:128],
e+hash_in[127:96], f+hash_in[95:64],
g+hash_in[63:32], h+hash_in[31:0]};
valid <= 1; running <= 0;
end
end
end
endmodule
// sha256_compress_tb.v
module sha256_compress_tb;
reg clk, rst_n, start;
reg [255:0] hash_in;
reg [511:0] block_in;
wire [255:0] hash_out;
wire valid;
sha256_compress uut (
.clk(clk), .rst_n(rst_n), .start(start),
.hash_in(hash_in), .block_in(block_in),
.hash_out(hash_out), .valid(valid)
);
always #5 clk = ~clk;
initial begin
clk = 0; rst_n = 0; start = 0;
#20 rst_n = 1;
// SHA-256 初始哈希值
hash_in = {32'h6a09e667, 32'hbb67ae85, 32'h3c6ef372, 32'ha54ff53a,
32'h510e527f, 32'h9b05688c, 32'h1f83d9ab, 32'h5be0cd19};
// 空消息填充块 (len=0, padding only)
block_in = 512'h00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000008000000000000000;
start = 1; #10; start = 0;
wait(valid);
$display("Hash: %064h", hash_out);
// 期望: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
$finish;
end
endmodule
1. 用空消息验证压缩函数输出是否等于 SHA-256("")[的]前半部分。
2. 实现消息调度为移位寄存器版本:只用 16 个寄存器,每轮移出最旧的消息字。
3. 计算 SHA-256 压缩函数的关键路径:从 h 到新的 a 需要经过多少级加法?
4. 思考:如果攻击者可以控制消息块,能否通过选择特定 W[t] 来降低压缩函数的安全性?
你已实现 SHA-256 压缩函数的硬件核心,掌握了消息调度、64 轮迭代和辅助函数的硬件映射。这是哈希算法的心脏!
获得徽章:🧬 HASH_CORE
推荐使用以下工具链进行课程实践:
# 安装 Verilator
sudo apt install verilator
# 安装 Icarus Verilog(可选)
sudo apt install iverilog
# 安装 GTKWave(波形查看器)
sudo apt install gtkwave
# 验证安装
verilator --lint-only --version
iverilog -V
密码学硬件实现的关键性能指标:
这些指标之间通常存在 trade-off,设计时需根据应用场景权衡。
SHA-256 基于 Merkle-Damgård 结构,存在长度扩展攻击:给定 H(m),攻击者可以计算 H(m ‖ padding ‖ m') 而不知道 m。
这就是为什么 H(K ‖ m) 不是安全的 MAC——必须使用 HMAC。
SHA-256 的 256 位输出意味着生日攻击需要约 2¹²⁸ 次哈希计算才能找到碰撞。目前没有已知的实用碰撞攻击。
本课涉及的核心概念和技术关系:
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 偏重面积和能效,服务器偏重吞吐量。