3、真随机数发生器(TRNG):TRNG原理、基于振荡器的TRNG设计、熵源评估与测试

3.1 真随机数到底“真”在哪?

做硬件安全这么多年,我经常被问到:“TRNG和PRNG到底有啥区别?”

说白了,PRNG(伪随机数发生器)是个数学算法。你给它一个种子,它就能吐出一长串看起来随机的数。但问题是——只要知道种子,序列就能完全复现。这在安全场景下,是个致命伤。

TRNG不一样。它不靠算法,而是靠物理世界的随机性。比如热噪声、抖动、放射性衰变。这些过程在物理上是不可预测的。你想想看,谁能精确预测一个电子的运动轨迹?没人。

所以,TRNG的核心价值在于:它的输出不可复现,不可预测。这是所有密码学安全的基石。

关键区别:
  • PRNG:确定性算法 + 种子 → 伪随机序列
  • TRNG:物理熵源 + 采样 → 真随机序列

3.2 基于振荡器的TRNG设计——我踩过的坑

在众多TRNG实现中,基于振荡器的方案是最常见的。为什么?因为它好做,成本低,适合集成到SoC里。

基本原理其实很简单:利用两个振荡器之间的相位抖动。一个慢速振荡器去采样一个快速振荡器。由于热噪声和1/f噪声的存在,每次采样的结果都会有一点点偏差。这个偏差,就是随机性的来源。

嗯,这里要注意。我当年第一次做这个设计时,天真地以为随便搭两个环振就能用。结果呢?测试出来的随机数质量惨不忍睹。后来才明白,振荡器的设计直接决定了熵源的质量

3.2.1 经典结构:双环振TRNG

我习惯用这种结构:

慢环振(低频) → 分频器 → D触发器的时钟端
快环振(高频) → D触发器的数据端
D触发器的输出 → 后处理模块

慢环振的频率通常在几十MHz,快环振在几百MHz到GHz级别。每次慢环振的上升沿到来时,D触发器采样快环振的当前电平。由于相位抖动,采样结果会在0和1之间随机跳变。

我的经验: 快环振的级数建议选奇数,比如3级或5级。级数太少,振荡不稳定;级数太多,抖动会被平均掉。我踩过7级的坑,随机性反而下降了。

3.2.2 设计中的“坑”与“避坑”

我曾经在一个项目里,TRNG的随机性测试死活过不了。查了三天,最后发现是电源噪声太大,导致振荡器的抖动被“淹没”了。你想想看,如果电源纹波是周期性的,那抖动就变成了确定性偏差,随机性自然就没了。

所以,我总结了几条避坑指南:

  • 电源隔离:TRNG的振荡器一定要用独立的LDO供电。别和数字逻辑共用电源。
  • 布局布线:振荡器要远离时钟树和高速I/O。我见过一个案例,TRNG被DDR的时钟串扰了,输出全是0x55。
  • 温度补偿:振荡器的频率会随温度漂移。如果漂移太大,采样窗口会错位。建议加一个温度传感器做校准。
警告: 不要直接用单端环振!单端环振对工艺偏差太敏感。我建议用差分环振,抗共模噪声能力强很多。

3.3 熵源评估——别被“看起来随机”骗了

设计完TRNG,怎么知道它好不好?光看波形是不够的。我见过太多“看起来随机”的序列,一上统计测试就原形毕露。

熵源评估,说白了就是回答三个问题:

  1. 输出是否均匀? 0和1的比例是不是接近50%?
  2. 是否有相关性? 相邻比特之间有没有依赖关系?
  3. 熵率够不够? 每比特携带了多少随机信息?

3.3.1 常用的统计测试套件

我个人最常用的是NIST SP 800-22测试套件。它包含15项测试,比如:

测试名称 检测目标 我的经验阈值
频率测试 0/1比例是否均匀 P-value > 0.01
游程测试 连续相同比特的长度分布 P-value > 0.01
块内频率测试 局部均匀性 P-value > 0.01
离散傅里叶变换测试 周期性模式 P-value > 0.01

注意,P-value大于0.01只是“通过”,不代表“优秀”。我一般要求所有测试的P-value都大于0.5,才敢说这个TRNG是可靠的。

一个容易被忽略的点: 测试数据量要足够大。NIST建议至少100万比特。我习惯采集1000万比特,分10组测试,看一致性。

3.3.2 在线监测——别等流片回来才后悔

我曾经吃过一次大亏。TRNG在实验室测试时一切正常,但到了客户现场,温度一高,随机性就下降了。为什么?因为振荡器的抖动随温度变化,熵源退化了。

从那以后,我坚持在TRNG里加一个在线熵源监测模块。它实时统计输出的0/1比例,如果偏离50%超过某个阈值(比如±5%),就触发告警,甚至直接切断输出。

这样做的好处是:你不需要等到系统出问题才去排查。TRNG一旦退化,安全机制就形同虚设。在线监测是最后一道防线。

3.4 后处理——把“毛坯”变成“精装”

原始熵源的输出往往有偏差。比如,由于工艺偏差,振荡器的占空比可能不是50%,导致输出中1的比例偏高。

这时候就需要后处理。我常用的方法有两种:

  • 冯·诺依曼校正器:检测相邻比特对,如果是“01”输出0,“10”输出1,“00”和“11”丢弃。简单有效,但吞吐率会下降。
  • 哈希提取:用SHA-256或类似算法对原始数据进行压缩。能有效去除偏差,但硬件开销大。

我个人习惯的做法是:先用冯·诺依曼校正器做一级处理,再用一个轻量级的LFSR做白化。这样既保证了随机性,又控制了面积和功耗。

小技巧: 后处理模块的时钟频率不要和振荡器耦合。我见过有人直接把后处理时钟接在快环振上,结果形成了正反馈,随机性反而变差了。

3.5 测试与验证——实战中的“最后一公里”

TRNG的测试,不能只靠仿真。我建议在FPGA上做原型验证,采集真实数据跑NIST测试。FPGA的布局布线环境和ASIC不同,但至少能验证架构的正确性。

测试流程我一般这样安排:

  1. 常温测试:25°C,采集1000万比特,跑NIST全套。
  2. 高低温测试:-40°C和85°C,各采集500万比特,看温度漂移。
  3. 电压拉偏测试:核心电压±10%,看电源敏感度。
  4. 长期稳定性测试:连续运行72小时,每小时采集一次数据,看是否有退化趋势。

我记得有一次,TRNG在72小时测试中,第48小时突然出现了一组P-value低于0.01的数据。查了半天,发现是芯片温度升高后,一个旁路电容的ESR变化了,导致电源噪声增大。换了电容后问题解决。这种问题,不做长期测试根本发现不了。

最后提醒一句: TRNG的测试报告一定要保留原始数据。客户审计时,光说“通过了NIST测试”是不够的,你得能拿出原始比特流和P-value列表。

好了,关于TRNG的原理、设计和测试,我就讲这么多。下一章我们聊聊物理不可克隆函数(PUF),那又是一个很有意思的话题。