生成器的类别

RngCore trait 是所有 随机数据来源 所必须实现的。但究竟什么是随机数据来源呢?

这一章涉及一些理论;可以参考 支持的 RNGs 一章。


#![allow(unused)]
fn main() {
extern crate rand;
extern crate rand_pcg;
// prepare a non-deterministic random number generator:
let mut rng = rand::thread_rng();

// prepare a deterministic generator:
use rand::SeedableRng;
let mut rng = rand_pcg::Pcg32::seed_from_u64(123);
}

真随机数 TRNGs

一个真正的随机数生成器 (TRNG: true random number generator) 是通过观察某些自然过程,比如原子衰退或热噪声来生成随机数。 这些过程是真正随机的还是实际上确定的, 比如宇宙自身可以是一个模拟系统,但都不是这里我们所关心的。 对于我们来说,只要能与真正的随机性没有区别就足够了。

要注意,这些过程时常有倾向性, 所以必须采用某种消除倾向性 (debiasing) 的类型 来产生我们想要的无倾向性的随机数据。

伪随机数 PRNGs

CPU 当然应该确切地进行计算,然而事实证明, 它也能很好地模拟随机过程。 大多数伪随机数生成器 (PRNG: pseudo-random number generators) 是确定性的,可以被定义为:

  • 有某种初始化的状态 (state)
  • 是一个从状态中计算随机值的函数
  • 是一个进入下个状态的函数
  • (可以是)从种子或者秘钥中获得初始状态的一个函数

这些伪随机数的确定性有时可以非常有用: 它让一场模拟行为、随机产生的艺术作品或游戏可以准确地重复; 产生的这种结果就是随机种子。 你可以在 移植性 这一章阅读细节。 注意,仅仅是确定性还无法重现结果。

伪随机数另一个好处是速度很快: 有些算法需要对每个随机值只进行少量的 CPU 操作, 所以这比大多数真随机数生成器生成的速度快得多。

也要注意,PRNGs 有以下限制:

  • 它们与随机种子一样不健壮:如果种子和算法已知或可推测, 那么生成的序列中仅有一小部分结果是随机。
  • 由于状态的大小通常是固定的,在生成器自身循环和重复的时候, 仅能生成有限的随机数。
  • 有些算法通过观测少量的值就能轻易被预测, 而且这些算法之外,很多算法并不清楚会不会被破解。

加密级安全的 PRNGs

加密级安全的 PRNGs (CSPRNGs: Cryptographically secure pseudo-random number generators) 是 PRNGs 的子集,而且被认为是安全的。即

  • 它们的状态足够多,以至于只尝试所有初始值的暴力破解方法, 不太可能找到生成观测值的初始状态;
  • 除了暴力破解方法之外,没有其他的算法可以足够好地预测下一个输出值。

安全的生成器 (CSPRNGs) 不仅需要安全的算法, 还需要安全且足够多的随机种子(通常是 256 位), 以及能抵挡住侧信道攻击(即防止攻击者读取内部状态)。

有些 CSPRNGs 还得满足第三种性质:抗回溯。 即使攻击者发现了当前内部状态的值,他也不可能计算出 PRNG 过去的输出值。 这暗含了,所有将来的输出值是缺乏抵抗力的。

基于硬件的 HRNGs

基于硬件的随机数生成器 (HRNG: hardware random number generator) 是理论上从某些 TRNG 到数字信息领域的延伸。 实际上, HRNGs 可能使用一个 PRNG 来消除 TRNG 的倾向性。 即使 HRNG 背后是 TRNG ,但 HRNG 不能保证是安全的。 TRNG 本身可能生成不了足够的熵(即很容易预测), 或者信号放大 (signal amplification) 和 去过程倾向性 (debias process) 可能有缺陷。

HRNGs 可能用来给 PRNGs 提供随机种子, 虽然这通常不是获取安全种子的唯一方式。 HRNGs 或许可以完全替代 PRNGs , 虽然这通常不是一个满意的方法, 因为现在已经有非常快速和健壮的 PRNGs 软件, 而且软件实现比验证硬件要容易很多。

因为 PRNGs 需要随机种子必须是安全的, 所以 HRNGs 可以用来提供种子,或者甚至于替代 PRNGs 。 然而我们的目标通常只是产生不可预测的随机值, 还有一些可以替代 TRNGs 的方法。

信息熵 Entropy

正如上面提到的,一个 CSPRNG 要是安全的,其种子的值也必须是安全的。 熵可以在以下两个方面被使用:

  • 衡量一堆数据中未知信息的的数量
  • 当作一堆未知的数据

理想情况下,一个随机的布尔值或者抛掷一枚硬币有 1 bit 熵 (bit of entropy) , 如果这个值有倾向性,熵的数量就会更少。 香农熵 (Shannon Entropy) 就试图来衡量这种情况。

比如一个 Unix 时间戳(从 1970 年以秒计算)包含了高精度和低精度的数据。 这通常是 32-bit 数字,但是熵的大小取决于一个假想攻击者 (hypothetical attacker) 可能以多少准确度猜出这个数字。 如果这个攻击者以接近分钟的准确度猜中数字,熵大约有 6 bits (2^6 = 64) ; 如果他猜中的准确度接近秒,则熵为 0 bit 。 JitterRng 生成器使用这种概念,不使用 HRNG 来清除熵; 它使用纳秒级精度的计时器,在对计时器的质量进行几次测试之后, 保守地假设每个时间戳只有一些熵。