规则30 伪随机数 密码学 PRNG硬件
深入分析规则30的混沌行为,理解确定性系统如何产生伪随机序列,并实现一个基于规则30的硬件伪随机数生成器(PRNG)。
规则30(LUT = 00011110)是Wolfram在1984年发现的"最简单的混沌系统"。它的行为令人震惊:
规则30的转移函数:
f(L, C, R) = L XOR (C OR R)
验证:000→0, 001→1, 010→1, 011→1, 100→1, 101→0, 110→0, 111→0 ✓
等价布尔式:f = L ⊕ (C ∨ R)
观察规则30的演化图案,你会发现:
信息传播方向分析:
对于规则30:f(L,C,R) = L ⊕ (C ∨ R)
右侧信号传播速度:v_R = 1(每步向右移动1格)
左侧信号传播速度:v_L = -1,但被规则"吸收"
这解释了为什么左半边呈现三角形——左侧信息被限制在光锥内
Wolfram在1985年提出用规则30的中心列作为伪随机数序列。具体方法:
提取方法:在每一步演化后,取中心元胞的值作为随机位
序列:r_0, r_1, r_2, ...,其中 r_t = CA_{N/2}(t)
这是一个确定性过程,但输出序列在统计上与真随机无法区分
| 测试 | 结果 | 说明 |
|---|---|---|
| 频率测试 | ✅ 通过 | 0和1的比例接近1:1 |
| 游程测试 | ✅ 通过 | 连续0/1的长度分布正确 |
| 自相关测试 | ✅ 通过 | 序列与自身移位版本不相关 |
| Diehard测试套件 | ✅ 通过 | 全面的随机性测试 |
| 线性复杂度 | ✅ 高 | 不可用短LFSR近似 |
// ============================================================================
// prng_rule30.v - 基于规则30的硬件伪随机数生成器
// 从中心列提取随机位,支持多位并行输出
// ============================================================================
module prng_rule30 #(
parameter WIDTH = 64, // CA网格宽度(建议≥32)
parameter OUT_WIDTH = 32 // 随机数输出位宽
)(
input wire clk,
input wire rst_n,
input wire enable, // 使能
input wire init, // 初始化
input wire [WIDTH-1:0] seed, // 初始种子
output wire [OUT_WIDTH-1:0] random_out, // 随机数输出
output wire valid, // 输出有效
output wire [WIDTH-1:0] state_debug // 调试:当前CA状态
);
// ---- CA状态寄存器 ----
reg [WIDTH-1:0] curr;
reg [WIDTH-1:0] nxt;
// ---- 规则30: f(L,C,R) = L XOR (C OR R) ----
// 优化实现:无需8:1 MUX,直接用布尔逻辑
wire left_ext = curr[WIDTH-1]; // 环形:左边界的左邻居
wire right_ext = curr[0]; // 环形:右边界的右邻居
genvar i;
generate
for (i = 0; i < WIDTH; i = i + 1) begin : gen_rule30
wire L = (i == 0) ? left_ext : curr[i-1];
wire C = curr[i];
wire R = (i == WIDTH-1) ? right_ext : curr[i+1];
assign nxt[i] = L ^ (C | R);
end
endgenerate
// ---- 状态更新 ----
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
curr <= {WIDTH{1'b0}};
else if (init)
curr <= seed;
else if (enable)
curr <= nxt;
end
// ---- 随机位提取 ----
// 方法1:取中心列连续OUT_WIDTH步的值(需要OUT_WIDTH步才能输出一个数)
// 方法2:从当前状态的多列并行提取(1步即可输出)
// 这里采用方法2:从网格中均匀采样OUT_WIDTH个位
// 采样间隔 = WIDTH / OUT_WIDTH
localparam SAMPLE_GAP = WIDTH / OUT_WIDTH;
genvar j;
generate
for (j = 0; j < OUT_WIDTH; j = j + 1) begin : gen_sample
// 从右半部分采样(右半部分更混沌)
localparam IDX = WIDTH/2 + (j * SAMPLE_GAP);
// 确保索引在范围内
if (IDX < WIDTH)
assign random_out[j] = curr[IDX];
else
assign random_out[j] = curr[WIDTH-1];
end
endgenerate
assign valid = enable;
assign state_debug = curr;
endmodule
对于需要高速随机数的应用(如蒙特卡洛仿真),我们可以利用规则30的列独立性,从不同列同时提取随机位:
// ============================================================================
// prng_rule30_parallel.v - 高速并行规则30 PRNG
// 每时钟周期输出一个完整的随机数
// 使用多个CA列同时提取,通过列间延迟保证独立性
// ============================================================================
module prng_rule30_parallel #(
parameter WIDTH = 128, // 加宽CA以提供更多独立列
parameter OUT_W = 32 // 输出位宽
)(
input wire clk,
input wire rst_n,
input wire reseed, // 重新播种
input wire [WIDTH-1:0] new_seed,
output wire [OUT_W-1:0] rand_data, // 随机数据
output wire rand_valid // 数据有效
);
// ---- CA阵列 ----
reg [WIDTH-1:0] ca_state;
wire [WIDTH-1:0] ca_next;
// 规则30组合逻辑
genvar i;
generate
for (i = 0; i < WIDTH; i = i + 1) begin : gen_ca
wire L = (i == 0) ? ca_state[WIDTH-1] : ca_state[i-1];
wire C = ca_state[i];
wire R = (i == WIDTH-1) ? ca_state[0] : ca_state[i+1];
assign ca_next[i] = L ^ (C | R);
end
endgenerate
// ---- 采样逻辑 ----
// 从CA状态的右半部分均匀采样OUT_W个位
// 右半部分混沌度更高,随机性更好
localparam HALF = WIDTH / 2;
localparam GAP = HALF / OUT_W;
genvar k;
generate
for (k = 0; k < OUT_W; k = k + 1) begin : gen_out
assign rand_data[k] = ca_state[HALF + k * GAP];
end
endgenerate
// ---- 状态更新 ----
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
ca_state <= {WIDTH{1'b0}};
else if (reseed)
ca_state <= new_seed;
else
ca_state <= ca_next; // 每周期自动步进
end
assign rand_valid = ~reseed; // 非重新播种时输出有效
endmodule
李雅普诺夫指数衡量系统对初始条件的敏感性:
λ = lim(t→∞) (1/t) × Σ ln|δx(t)/δx(0)|
规则30的右半部分:λ > 0(混沌,初始条件敏感)
规则30的左半部分:λ ≈ 0(规则结构,不敏感)
正的李雅普诺夫指数是混沌的标志——微小的初始扰动被指数放大
对于有限宽度W的环形CA,状态空间大小为 2^W
因此最大周期 P ≤ 2^W
实际观测:
周期随W指数增长,对于WIDTH≥64,周期远超实际应用需求
| 特性 | 规则30 PRNG | LFSR |
|---|---|---|
| 线性度 | 非线性 | 线性 |
| 硬件开销 | 中等(XOR+OR per bit) | 极低(XOR+移位) |
| 随机性质量 | 极高 | 中等(通过多项式选择改善) |
| 可预测性 | 难以从输出推断状态 | 2n个输出位即可完全推断 |
| 周期 | 约2^(W/2) | 精确2^n-1(最长相移位) |
| 吞吐率 | 1 bit/cycle(单列) | 1 bit/cycle |
// ============================================================================
// prng_rule30_stat_tb.v - 规则30 PRNG统计测试
// 验证输出序列的频率分布和自相关性
// ============================================================================
\`timescale 1ns/1ps
module prng_rule30_stat_tb;
parameter WIDTH = 64;
parameter OUT_W = 8;
parameter SAMPLES = 10000; // 采样数
reg clk, rst_n, enable, init;
reg [WIDTH-1:0] seed;
wire [OUT_W-1:0] rand_out;
wire valid;
wire [WIDTH-1:0] debug;
prng_rule30 #(.WIDTH(WIDTH), .OUT_WIDTH(OUT_W)) dut (
.clk(clk), .rst_n(rst_n), .enable(enable),
.init(init), .seed(seed),
.random_out(rand_out), .valid(valid), .state_debug(debug)
);
initial clk = 0;
always #5 clk = ~clk;
// 统计计数器
integer counts [0:255]; // 对8位输出的256种值计数
integer total;
real chi_square;
real expected;
integer n;
initial begin
// 初始化计数器
for (n = 0; n < 256; n = n + 1) counts[n] = 0;
total = 0;
$dumpfile("prng_rule30.vcd");
$dumpvars(0, prng_rule30_stat_tb);
// 复位
rst_n = 0; enable = 0; init = 0;
#50 rst_n = 1;
// 初始化:中心位为1
seed = 64'h1 << 31;
init = 1; #10; init = 0;
// 采集样本
enable = 1;
for (n = 0; n < SAMPLES; n = n + 1) begin
@(posedge clk);
counts[rand_out] = counts[rand_out] + 1;
total = total + 1;
end
// 计算卡方统计量
expected = real'(total) / 256.0;
chi_square = 0.0;
for (n = 0; n < 256; n = n + 1) begin
chi_square = chi_square +
((real'(counts[n]) - expected) *
(real'(counts[n]) - expected)) / expected;
end
$display("=== Rule 30 PRNG Statistics ===");
$display("Samples: %0d", total);
$display("Expected per bin: %0.1f", expected);
$display("Chi-square: %0.2f", chi_square);
$display("Chi-square critical (df=255, p=0.05): 293.25");
if (chi_square < 293.25)
$display("✅ PASSED: Distribution appears uniform");
else
$display("❌ FAILED: Distribution may be non-uniform");
$finish;
end
endmodule
prng_rule30,增加一个"预热"计数器——初始化后先运行T步(不输出),再开始提取随机数。T应该是多少?为什么需要预热?
你已理解确定性系统如何产生混沌行为,并实现了基于规则30的硬件PRNG。
规则30揭示了一个深刻的哲学问题:完全确定的规则可以产生统计上不可预测的行为。这是"决定论混沌"的核心——可计算≠可预测。
元胞自动机课程 · 从Conway到Langton到Lattice Gas