阶段二哈希与认证 — 伪随机数生成器(PRNG/CSPRNG)使用确定性算法从种子生成看似随机的序列。CSPRNG 的安全性保证使其适用于密码学场景。
| 特性 | PRNG | CSPRNG |
|---|---|---|
| 下一个位测试 | 不保证 | 计算上不可行预测 |
| 状态泄露 | 可预测后续输出 | 不可预测前向和后向 |
| 周期 | 可能较短 | 实际无限(2^128+) |
| 应用 | 仿真、游戏 | 密钥生成、nonce |
线性反馈移位寄存器是最简单的硬件 PRNG。n 位 LFSR 的最大周期为 2ⁿ-1(本原多项式)。
// lfsr.v - 通用 LFSR 模块
module lfsr #(
parameter WIDTH = 16, // LFSR 位宽
parameter [WIDTH-1:0] TAPS = 16'hB400, // 反馈抽头位置
parameter [WIDTH-1:0] SEED = 16'hACE1 // 初始种子
)(
input wire clk,
input wire rst_n,
input wire enable,
output wire [WIDTH-1:0] data_out, // LFSR 状态输出
output wire msb // 最高位输出(随机位流)
);
reg [WIDTH-1:0] lfsr_reg;
// 计算反馈位:XOR 所有抽头位置
integer i;
reg feedback;
always @(*) begin
feedback = lfsr_reg[WIDTH-1]; // 最高位总是参与
for (i = WIDTH-2; i >= 0; i = i - 1) begin
if (TAPS[i]) feedback = feedback ^ lfsr_reg[i];
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
lfsr_reg <= SEED;
else if (enable)
lfsr_reg <= {lfsr_reg[WIDTH-2:0], feedback};
end
assign data_out = lfsr_reg;
assign msb = lfsr_reg[WIDTH-1];
endmodule
| 位宽 | 多项式(十六进制抽头) | 周期 |
|---|---|---|
| 8 | 0xB8 | 255 |
| 16 | 0xB400 | 65535 |
| 32 | 0x80200003 | 4,294,967,295 |
| 64 | 0x800000000000000B | 2⁶⁴-1 |
NIST SP 800-90A 推荐的 CTR-DRBG 使用 AES-CTR 模式作为密码学安全 PRNG:
// ctr_drbg.v - 基于 AES-CTR 的 CSPRNG
module ctr_drbg #(
parameter SEED_WIDTH = 256
)(
input wire clk,
input wire rst_n,
input wire reseed, // 重置种子
input wire [SEED_WIDTH-1:0] seed_in, // 新种子
input wire generate, // 请求输出
output reg [127:0] random_out, // 随机输出
output reg random_valid,
output reg reseed_required // 需要重置种子
);
// 内部状态
reg [127:0] key; // AES 密钥
reg [127:0] counter; // CTR 计数器
reg [31:0] reseed_counter; // 生成计数器
localparam MAX_REQUESTS = 32'h0000FFFF; // 最大请求数
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
key <= 128'h0;
counter <= 128'h0;
random_valid <= 0;
reseed_counter <= 0;
reseed_required <= 0;
end else if (reseed) begin
// 重置种子:用输入种子更新密钥和计数器
key <= seed_in[255:128];
counter <= seed_in[127:0];
reseed_counter <= 0;
reseed_required <= 0;
end else if (generate) begin
// CTR 模式:AES_Key(Counter++) 作为随机输出
counter <= counter + 128'd1;
reseed_counter <= reseed_counter + 1;
// 简化实现:实际需要 AES 加密
// random_out = AES_encrypt(key, counter)
// 这里用简化版本模拟
random_out <= counter ^ key;
random_valid <= 1;
if (reseed_counter >= MAX_REQUESTS)
reseed_required <= 1;
end else begin
random_valid <= 0;
end
end
endmodule
LFSR 的线性结构使其完全不适用于密码学——2n 位输出即可完全重构 n 位 LFSR。增强方法:
// shrinking_gen.v - 收缩生成器(密码学增强 LFSR)
module shrinking_gen (
input wire clk,
input wire rst_n,
input wire enable,
output reg random_bit,
output reg random_valid
);
// 控制 LFSR(决定是否输出)
reg [15:0] ctrl_lfsr;
// 数据 LFSR(提供输出位)
reg [15:0] data_lfsr;
// 16位本原多项式反馈
wire ctrl_fb = ctrl_lfsr[15] ^ ctrl_lfsr[14] ^ ctrl_lfsr[12] ^ ctrl_lfsr[3];
wire data_fb = data_lfsr[15] ^ data_lfsr[14] ^ data_lfsr[12] ^ data_lfsr[3];
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ctrl_lfsr <= 16'hACE1;
data_lfsr <= 16'hBEEF;
random_bit <= 0;
random_valid <= 0;
end else if (enable) begin
// 两个 LFSR 都步进
ctrl_lfsr <= {ctrl_lfsr[14:0], ctrl_fb};
data_lfsr <= {data_lfsr[14:0], data_fb};
// 收缩:仅当控制 LFSR 最高位为 1 时输出
if (ctrl_lfsr[15]) begin
random_bit <= data_lfsr[15];
random_valid <= 1;
end else begin
random_valid <= 0;
end
end else begin
random_valid <= 0;
end
end
endmodule
1. 实现 32 位 LFSR,验证其周期为 2³²-1。
2. 攻破一个 16 位 LFSR:给定 32 位输出序列,用 Berlekamp-Massey 算法恢复反馈多项式。
3. 实现 NIST SP 800-90A 的 Hash-DRBG(基于 SHA-256)。
4. 分析收缩生成器的安全性:输出速率是多少?是否存在可利用的统计偏差?
你已掌握 LFSR、CSPRNG 和增强型 PRNG 的硬件实现。理解了 LFSR 的线性弱点和非线性增强方法。密码学随机数是安全协议的生命线!
获得徽章:🎰 PRNG_MASTER
推荐使用以下工具链进行课程实践:
# 安装 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 偏重面积和能效,服务器偏重吞吐量。
本课涉及的核心概念和技术关系:
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 偏重面积和能效,服务器偏重吞吐量。