3.3 生成器类型

原文链接: https://rust-random.github.io/book/guide-gen.html

上一节介绍了 RngCore,所有随机数据源都必须实现该 trait。但随机数据源究竟是什么?

本节讨论理论;另请参阅随机数生成器一章。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
use rand::{RngExt, SeedableRng};

# fn main() {
// 准备一个非确定性随机数生成器:
let mut rng = rand::rng();
println!("{}", rng.random::<i32>()); // 打印一个未知值

// 准备一个确定性生成器:
let mut rng = rand::rngs::ChaCha8Rng::seed_from_u64(123);
println!("{}", rng.random::<i32>()); // 打印 -416273517
# }

真随机数生成器

真随机数生成器(TRNG)通过观测某种自然过程来产生随机数,例如原子衰变或热噪声。(这些过程是否真正随机,抑或实际上是确定性的——例如宇宙本身是否是模拟——在此无关紧要。对我们的目的而言,只要它们与真随机性无法区分即可。)

请注意,这些过程往往有偏倚,因此必须使用某种去偏方法才能得到我们想要的无偏随机数据。

伪随机数生成器

CPU 当然应当确定性计算,但它们能很好地模拟随机过程。大多数伪随机数生成器是确定性的,可以仅由以下要素定义:

  • 初始状态
  • 从状态计算随机值的函数
  • 推进到下一状态的函数
  • (可选)从种子或密钥派生初始状态的函数

这些生成器是确定性的,有时非常有用:它允许模拟、随机艺术作品或游戏完全重复,产生仅由种子决定的结果。更多内容请参阅可复现性一章(注意仅有确定性不足以保证可复现性)。

PRNG 的另一大吸引力是速度:其中一些算法每个随机值只需几次 CPU 运算,因此能比大多数 TRNG 更快地按需产生随机数据。

但 PRNG 也有若干局限:

  • 强度不超过种子:若种子已知或可猜测,且算法已知(或被猜出),则可能的输出序列只有很少几种。
  • 由于状态大小通常固定,在生成器循环重复之前只能产生有限数量的输出值。
  • 若干算法在看到少量值后很容易被预测,而对许多其他算法尚不清楚是否可被「破解」。

密码学安全伪随机数生成器

密码学安全伪随机数生成器(CSPRNG)是被认为安全的 PRNG 子集。即:

  • 其状态足够大,使得暴力尝试所有初始值来找到产生已观测输出序列的初始状态并不可行,
  • 且不存在明显优于暴力方法的算法,足以预测下一个输出值。

实现安全生成不仅需要安全算法(CSPRNG),还需要安全且足够大的种子值(通常 256 位),以及防范侧信道攻击(即防止攻击者读取内部状态)。

部分 CSPRNG 还满足第三个性质:

  • 若攻击者在发现 PRNG 当前内部状态后,仍无法计算先前的输出值(意味着未来所有输出都已泄露),则该 CSPRNG 具有回溯抗性。

硬件随机数生成器

硬件随机数生成器(HRNG)在理论上是将某种 TRNG 适配为数字信息的设备。实践中,可能使用 PRNG 对 TRNG 去偏。尽管 HRNG 有底层 TRNG,但并不保证安全:TRNG 本身可能熵不足(即可预测性过高),或信号放大与去偏过程可能有缺陷。

HRNG 可用于为 PRNG 提供种子,尽管通常这不是获得安全种子的唯一方式(见下一节)。HRNG 也可能完全替代 PRNG,但由于我们现在已有非常快且很强的软件 PRNG,且软件实现比硬件更易验证,这通常不是首选方案。

由于 PRNG 需要随机种子才能保证安全,HRNG 可提供该种子,甚至替代对 PRNG 的需求。然而,目标通常「仅」是产生不可预测的随机值,因此真随机数生成器有可接受的替代方案(见下一节)。

熵

如上所述,要使 CSPRNG 安全,其种子值也必须安全。熵一词有两种用法:

  • 作为某段数据中未知信息量的度量
  • 作为一段未知数据

理想情况下,随机布尔值或掷硬币有 1 位熵,但若值有偏,熵会更少。香农熵试图度量这一点。

例如,Unix 时间戳(自 1970 年初起的秒数)同时包含高分辨率和低分辨率数据。这通常是 32 位数字,但熵的量取决于假想攻击者能多么精确地猜测该数字。若攻击者能精确到分钟,可能约为 6 位(2^6 = 64);若能精确到秒,则为 0 位。JitterRng 利用这一概念在没有 HRNG 的情况下搜集熵(使用纳秒级计时器,并在对计时器质量进行若干测试后,保守地假设每个时间戳仅能提供几位熵)。

最后修改 August 23, 2026: 更新 (499855b16)