3. 真随机数发生器(TRNG):基于物理噪声源的高质量随机数生成原理与设计

真随机数发生器,圈里人常叫它TRNG。这玩意儿在芯片安全里,地位可不一般。你想想看,密钥要是能被猜出来,那加密就等于没穿衣服。TRNG就是负责生成那种“连上帝都不知道下一个数是啥”的随机数。

我入行那会儿,第一次接触TRNG,觉得不就是个随机数嘛,软件里rand()函数也能搞。后来被前辈狠狠教育了一顿——软件随机数是伪随机,是算法算出来的,有周期!而TRNG靠的是物理世界的“真随机”,比如热噪声、抖动。嗯,这里要注意,这两者有本质区别。

3.1 物理噪声源:TRNG的“心脏”

TRNG的核心,说白了就是找一个物理过程,它本身是随机的、不可预测的。我个人习惯把噪声源分成三类:

  • 热噪声:电阻里电子的热运动。温度越高,噪声越大。优点是带宽宽,缺点是幅度小,需要放大。
  • 抖动噪声:振荡器周期的不稳定性。比如环形振荡器,每个门的延迟都在微小的波动。我在项目中遇到过,这种噪声源对电源噪声特别敏感,一不小心就“偏”了。
  • 亚稳态噪声:触发器在建立/保持时间窗口内采样,输出不确定。这玩意儿风险大,但随机性极好。

我曾经踩过一个坑:选用了纯热噪声源,结果流片回来发现,低温下噪声幅度太小,随机数生成速率直接掉到零。后来我学乖了,设计时一定要留足余量,或者搞个混合噪声源。

3.2 熵源设计:从物理噪声到“数字熵”

物理噪声是模拟信号,得把它变成数字的“0”和“1”。这个过程叫量化。常见的做法是:

  1. 直接采样法:用高速ADC采样噪声电压,取最低有效位。简单粗暴,但ADC功耗大。
  2. 振荡器采样法:用两个不同频率的振荡器,一个快一个慢。用慢时钟去采样快时钟的相位。抖动会让采样结果随机。
  3. 环形振荡器法:奇数个反相器首尾相连,振荡频率受噪声调制。我比较喜欢这种,因为它全数字,好移植。

核心指标:熵率

熵率衡量的是每个输出比特里,有多少“真随机”的成分。理想情况是1比特/比特。但实际中,由于噪声源有相关性,熵率往往低于1。设计时,我们通常要留出20%-30%的余量。

下面这张图,是我自己总结的TRNG核心逻辑。你看,从物理噪声到最终随机数,中间要经过好几道关卡。

TRNG核心架构流程图 物理噪声源 (热噪声/抖动/亚稳态) 熵提取电路 (振荡器/ADC/亚稳态) 数字化与后处理 (冯·诺依曼/Hash/去偏) 输出 在线测试/健康监测 图:TRNG从物理噪声到随机数输出的完整流程 关键设计要点: 1. 噪声源必须独立于数字电路,避免被攻击者预测或控制 2. 后处理环节不能“杀死”熵,要保留原始随机性 3. 健康监测是必须的!一旦噪声源失效,要能立刻报警 4. 布局布线时,TRNG要远离大功率数字模块,防止串扰

3.3 后处理技术:去偏与提取

直接从噪声源拿到的比特流,往往有偏——比如“1”比“0”多。这不行,得处理。常用的后处理算法有:

  • 冯·诺依曼去偏器:看连续两个比特,01输出0,10输出1,00和11丢弃。简单,但吞吐率会降到1/4。
  • 哈希提取:用SHA-256或类似算法,把原始比特“搅拌”一下。安全性高,但面积大。
  • LFSR(线性反馈移位寄存器):把原始比特作为种子,LFSR输出。注意,LFSR本身是确定的,所以只能做“白化”,不能增加熵。

我的经验:冯·诺依曼去偏器虽然简单,但如果你对吞吐率有要求,最好用哈希。我在一个IoT芯片项目里,为了省面积用了冯·诺依曼,结果随机数生成速率不够,导致密钥生成时间过长,差点没通过认证。后来改成轻量级哈希,才搞定。

3.4 在线测试与健康监测

TRNG最怕什么?怕它“坏了”你还不知道。比如噪声源被干扰,或者干脆停振了。所以,健康监测是TRNG的“安全带”。

我建议至少做以下三项测试:

测试项 检测内容 触发条件
重复计数测试 连续相同比特的数量 超过阈值(如64个连续0)
自适应比例测试 窗口内“1”的比例 偏离50%超过±15%
运行测试 0/1交替的模式 模式过于规律

这些测试在芯片上电后要持续运行。一旦发现异常,立刻切断随机数输出,并上报安全中断。我曾经见过一个设计,健康监测只做了上电自检,结果运行中电源纹波变大,TRNG输出质量下降,整个加密系统都跟着遭殃。

3.5 设计实例:一个简单的环形振荡器TRNG

说了这么多,咱们来点实际的。下面是一个基于环形振荡器的TRNG核心代码(Verilog描述)。

module trng_ring_osc (
    input  wire        clk,        // 系统时钟
    input  wire        rst_n,      // 复位
    input  wire        enable,     // 使能
    output reg  [7:0]  random_out, // 8位随机数
    output reg         valid       // 数据有效标志
);

    // 环形振荡器:3级反相器
    wire osc_out;
    reg  osc_en;
    wire osc_feedback;

    assign osc_feedback = ~osc_out;
    
    // 使能控制,防止振荡器一直跑
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            osc_en <= 1'b0;
        else if (enable)
            osc_en <= 1'b1;
        else
            osc_en <= 1'b0;
    end

    // 3级环形振荡器(实际中需加延迟单元)
    assign #1 osc_out = osc_en ? osc_feedback : 1'b0;

    // 采样与累加
    reg [7:0] shift_reg;
    reg [3:0] sample_cnt;

    always @(posedge osc_out or negedge rst_n) begin
        if (!rst_n) begin
            shift_reg <= 8'b0;
            sample_cnt <= 4'b0;
            valid <= 1'b0;
        end else if (enable) begin
            shift_reg <= {shift_reg[6:0], osc_out};
            sample_cnt <= sample_cnt + 1'b1;
            if (sample_cnt == 4'd7) begin
                random_out <= shift_reg;
                valid <= 1'b1;
            end
        end
    end

endmodule

警告:上面的代码只是一个教学示例,不能直接用于量产芯片!实际设计中,环形振荡器需要加延迟单元(如门控延迟链),并且要经过严格的蒙特卡洛仿真,确保PVT(工艺、电压、温度)变化下仍能起振。另外,采样时钟和振荡器之间要做好隔离,防止确定性耦合。

3.6 安全考量:TRNG的抗攻击设计

TRNG是安全芯片的“命门”。攻击者最喜欢搞它。常见的攻击方式有:

  • 频率注入攻击:在电源或地线上注入特定频率的噪声,让振荡器“锁定”在某个频率上,失去随机性。
  • 温度攻击:极端温度下,噪声源特性改变,熵率下降。
  • 电磁干扰:强电磁场直接干扰振荡器。

怎么防?我个人习惯用这几招:

  1. 多源融合:同时用热噪声和抖动噪声,攻击者很难同时干扰两个不同物理源。
  2. 屏蔽与隔离:TRNG模块用独立的电源域和地域,周围加保护环。
  3. 动态阈值:健康监测的阈值不是固定的,而是根据当前环境动态调整。比如温度高了,就放宽一点。

我记得有一次,一个客户的产品在EMC测试时,TRNG输出突然变成全0。查了半天,发现是电磁干扰让振荡器停振了。后来我们在振荡器输出端加了一个“心跳检测”电路,一旦发现振荡器停了,立刻切换到备用噪声源。这才过了认证。

3.7 质量评估:怎么知道你做的TRNG好不好?

TRNG做出来,总得有个标准衡量。业界最常用的是NIST SP 800-22和AIS-31。我建议至少跑以下测试:

  • 频数测试:看0和1的数量是否接近。
  • 游程测试:看连续相同比特的分布是否正常。
  • 块内频数测试:把数据分成块,看每块里1的比例。
  • 离散傅里叶变换测试:看频谱上有没有周期性峰值。

这些测试,说白了就是“找规律”。如果TRNG输出里能找到任何规律,那它就是不合格的。我一般会采集至少1百万个比特,跑全套NIST测试,全部通过才算完。

一句话总结:TRNG设计,物理噪声源是基础,后处理是保障,健康监测是底线。三者缺一不可。

好了,关于TRNG的核心原理和设计,我就聊到这儿。这东西说难不难,说简单也不简单。关键是要理解物理随机性的本质,以及如何把它“驯服”成可用的数字随机数。下次你看到芯片里的随机数,可以想想——它背后,可能是一个小小的振荡器,在热噪声的驱动下,永不停歇地跳动着。


公众号:蓝海资料掘金营,微信deep3321