4. 离线统计测试:NIST测试套件详解

好,咱们进入正题。离线统计测试,说白了就是拿一堆随机数,用数学方法去“审问”它——你到底是不是真随机?NIST SP 800-22 是这个领域的圣经。我这些年做硬件安全,几乎每个项目都要跑一遍这套测试。今天我就把几个最核心的测试项掰开揉碎了讲给你听。

4.1 频率测试(Mono-bit Frequency Test)

这是最基础、也最直观的测试。它只问一个问题:你的序列里,0 和 1 的数量是不是差不多?

理想情况下,一个真随机序列应该有接近一半的 0 和一半的 1。如果偏差太大,说明你的熵源可能有问题。比如,我遇到过某个 TRNG 芯片,因为电源噪声耦合进了 VCO,导致输出 1 的比例总是比 0 多 2% 左右。频率测试第一个就把它揪出来了。

核心公式:

S_n = sum(2*bit_i - 1)   // 将 0→-1, 1→+1 后求和
P_value = erfc(|S_n| / sqrt(2*n))

其中 n 是序列长度,erfc 是互补误差函数。P_value 小于 0.01 就判定为非随机。

我的经验:频率测试对序列长度很敏感。太短(比如 n < 100)测不出偏差;太长(n > 10^6)又可能因为微小但统计显著的偏差而误判。我个人习惯用 n = 10000 作为标准长度。

4.2 块内频数测试(Frequency Test within a Block)

频率测试看的是全局。但有时候,全局比例是 50/50,局部却有问题。比如,前 1000 位全是 0,后 1000 位全是 1——整体还是平衡的,但这显然不是随机。

块内频数测试就是干这个的。它把序列切成 M 位一块,分别统计每块里 1 的比例,然后用卡方检验看这些比例是否均匀。

参数 推荐值 说明
块大小 M 100 ~ 1000 M 太小则块数太多,统计不稳定;M 太大则失去局部检测能力
序列总长 n ≥ 100 * M 保证至少有 100 个块,卡方检验才有效

嗯,这里要注意:块大小 M 的选择很关键。我见过有人用 M=8,结果每个块只有 8 位,统计量根本不够,测试形同虚设。我一般取 M=128,既够统计量,又能捕捉到中等尺度的局部偏差。

4.3 游程测试(Runs Test)

游程,就是连续相同位的序列。比如 000111000 里有三个游程:000、111、000。游程测试检查的是:你的序列里,游程的数量和长度是否在预期范围内?

为什么会这样?因为真随机序列里,游程的分布是有规律的。太长的游程(比如连续 20 个 1)出现概率极低。如果出现了,说明你的随机源可能有记忆效应——也就是状态依赖。

我曾经踩过的坑:有一次测试一个基于环形振荡器的 TRNG,游程测试总是不过。查了很久才发现,是振荡器之间的耦合导致了一个 3 位的偏好模式反复出现。频率测试完全正常,但游程测试把它暴露了。所以,频率测试和游程测试一定要搭配使用,缺一不可。

4.4 离散傅里叶变换测试(DFT Test)

这个测试稍微硬核一点。它把随机序列当成一个时域信号,做 FFT 变换到频域,然后检查频谱中是否有明显的尖峰。

你想想看,如果序列是纯随机的,它的频谱应该是平坦的——白噪声嘛。但如果存在周期性成分,频谱上就会出现峰值。比如,某个 TRNG 因为 50Hz 工频干扰,输出里就带了一个 50Hz 的周期分量。DFT 测试能把它抓出来。

具体做法是:

  1. 将比特序列映射为 ±1 序列
  2. 做离散傅里叶变换,得到频谱
  3. 统计频谱中超过某个阈值的峰值数量
  4. 与理论预期比较,计算 P 值

关键参数:阈值通常取 sqrt(n * log(1/0.05)),对应 95% 置信水平。超过这个阈值的峰值数量如果太多或太少,都说明有问题。

4.5 测试参数选择与 P 值解读

跑 NIST 测试,参数选不对,结果就是废纸。我总结了几条铁律:

  • 序列长度 n:NIST 官方建议 n ≥ 10^6。但实际项目中,我经常用 n = 10^5 做快速筛选,通过后再用 10^6 做正式认证。
  • 显著性水平 α:通常取 0.01。这意味着有 1% 的概率把真随机误判为非随机。如果你做的是金融级安全,建议取 0.001。
  • P 值解读:P ≥ 0.01 通过,P < 0.01 不通过。但要注意,P 值接近 0.01 时(比如 0.011),不要急着下结论。我建议多测几组序列,看 P 值的分布是否均匀。
P 值范围 解读 建议操作
0.5 ~ 1.0 非常随机 继续其他测试
0.1 ~ 0.5 正常随机 正常通过
0.01 ~ 0.1 边缘 增加样本量复测
< 0.01 不随机 检查熵源

4.6 测试序列长度要求

这个问题很多人问。NIST 对每个测试都有最小序列长度要求,我整理了一张表:

测试名称 最小序列长度 推荐长度
频率测试 100 10,000
块内频数测试 100 * M 100,000
游程测试 100 10,000
DFT 测试 1,000 100,000

但说实话,这些最小值只是理论下限。你想想看,用 100 位去判断一个随机数发生器好不好,这本身就不靠谱。我个人的底线是:每个测试至少用 10^5 位,整套测试至少用 10^6 位。低于这个量级,测试结果没有统计意义。

一个小技巧:如果你需要快速迭代测试(比如调试阶段),可以用 10^4 位跑一遍所有测试,大概 1 秒出结果。等参数调好了,再用 10^6 位做正式测试。这样效率高很多。

NIST 统计测试流程 原始随机序列 预处理:长度检查、格式转换 频率测试 全局比例检查 块内频数测试 局部偏差检测 游程测试 记忆效应检测 DFT 测试 周期性检测 P 值计算与判定 P ≥ 0.01 通过 | P < 0.01 不通过 建议:每个测试至少 10⁵ 位 整套测试至少 10⁶ 位

这张图把整个测试流程串起来了。从原始序列出发,经过预处理,分四条路径并行测试,最后汇聚到 P 值判定。你每次跑测试,脑子里都要有这个流程——知道每一步在干什么,为什么这么干。