『Odaily星球日报』科普:真随机数和伪随机数

比特币用户很喜欢讨论“非对称加密”、“椭圆曲线”、“量子计算机”这类高深莫测的话题 , 然后再以一种非常莫名其妙的方式把币弄丢 , 比如说:“随机” 。
『Odaily星球日报』科普:真随机数和伪随机数
本文插图
历史上多起各品牌的钱包用户丢币事件 , 都是因为随机函数存在问题 。
随机很重要 , 对于比特币这种密码学电子货币来说 , 尤其重要 。 可惜社区内对于随机的讨论并不多 , 导致很多人缺乏正确的认识 , 因此 , 我们今天就和大家聊聊随机 。
说到随机 , 有两个必须要搞清楚的概念:“真随机数生成器”(TRNG)和伪随机数生成器(PRNG) 。
大部分计算机程序和语言中的随机函数 , 都是伪随机数生成器 , 它们都是由确定的算法 , 通过一个“种子”(比如“时间”) , 来产生“看起来随机”的结果 。
毫无疑问 , 任何人只要知道算法和种子 , 或者之前已经产生了的随机数 , 都可能获得接下来随机数序列的信息 。 因为它们的可预测性 , 在密码学上并不安全 , 所以我们称其为“伪随机” 。 这种随机数 , 用来让游戏里的小人跑跑路没多大问题 , 如果用来生成比特币私钥 , 那可就太不安全了 。
再说说真随机数生成器 , 中文维基中 , 将“硬件随机数生成器”(HRNG)等同于真随机数生成器 , 这其实并不十分准确 , 严格意义上的真随机可能仅存在于量子力学之中 , 我们当前所想要的(或者所能要的) , 并不是这种随机 。
我们其实想要一种不可预测的、统计意义上的、密码学安全的随机数 , 只要能做到这一点的随机数生成器 , 都可以称其为真随机数生成器 。 这种真随机 , 并不一定非得是特殊设计的硬件 , Linux操作系统内核中的随机数生成器(/dev/random) , 维护了一个熵池(搜集硬件噪声 , 如:键盘、鼠标操作、网络信号强度变化等) , 使得它能够提供最大可能的随机数据熵 , 因此同样是高品质的真随机数生成器 。
不过/dev/random是阻塞的 , 也就是说 , 如果熵池空了 , 对于/dev/random的读操作将被挂起 , 直到收集到足够的环境噪声为止 。
因此 , 在开发程序时 , 我们应使用/dev/urandom , 作为/dev/random的一个副本 , 它不会阻塞 , 但其输出的熵可能会小于/dev/random 。
好了 , 在说了这么多之后 , 在我们开发比特币应用时 , 应该使用何种随机数生成器来生成私钥呢?
答案很简单:urandom 。 永远只用urandom 。
不要使用任何第三方的随机数解决方案 , 哪怕是一些高级的安全库 , 所提供的声称“非常安全”的随机函数 。 因为它们都是用户态的密码学随机数生成器 , 而urandom是内核态的随机数生成器 , 内核有权访问裸设备的熵 , 内核可以确保 , 不在应用程序间 , 共享相同的状态 。
【『Odaily星球日报』科普:真随机数和伪随机数】历史上 , 无数次随机数失败案例 , 大多出现在用户态的随机数生成器 , 而且 , 用户态的随机数生成器几乎总是要依赖于 , 内核态的随机数生成器(如果不依赖 , 那风险则更大) , 除了没准儿能简化您的某些开发工作 , 丝毫看不出任何额外的好处 , 反而增加了因引入第三方代码 , 所可能导致的潜在安全风险 。
因此 , 开发者在需要密码学安全的随机数时 , 应使用urandom 。
最后 , 有小朋友问 , 你们的BITHD硬件钱包生成的是真随机数吗?
这里回答一下:当然是啦~
BITHD的芯片是有硬件随机数发生器的 , 它会通过获取物理噪声源来生成真随机数 , 这个是不可预测 , 不可探测的 , 是真正的随机源 。


    推荐阅读