第12课:伪随机数生成器

阶段二哈希与认证 — 伪随机数生成器(PRNG/CSPRNG)使用确定性算法从种子生成看似随机的序列。CSPRNG 的安全性保证使其适用于密码学场景。

1. PRNG vs CSPRNG

特性PRNGCSPRNG
下一个位测试不保证计算上不可行预测
状态泄露可预测后续输出不可预测前向和后向
周期可能较短实际无限(2^128+)
应用仿真、游戏密钥生成、nonce

2. LFSR:最简单的 PRNG

线性反馈移位寄存器是最简单的硬件 PRNG。n 位 LFSR 的最大周期为 2ⁿ-1(本原多项式)。

✅Verilator验证通过
// 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

常用本原多项式

位宽多项式(十六进制抽头)周期
80xB8255
160xB40065535
320x802000034,294,967,295
640x800000000000000B2⁶⁴-1

3. 基于 AES 的 CSPRNG(CTR-DRBG)

NIST SP 800-90A 推荐的 CTR-DRBG 使用 AES-CTR 模式作为密码学安全 PRNG:

✅Verilator验证通过
// 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

4. LFSR 的密码学弱点与增强

LFSR 的线性结构使其完全不适用于密码学——2n 位输出即可完全重构 n 位 LFSR。增强方法:

✅Verilator验证通过
// 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!");

🔧 Verilator 编译仿真完整流程

# 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!");

🔧 Verilator 编译仿真完整流程

# 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 偏重面积和能效,服务器偏重吞吐量。