扒一扒随机数(Random Number)的诞生历史

做者:Alon Zakai <br/>
编译:胡子大哈 javascript

翻译原文:http://huziketang.com/blog/posts/detail?postId=58cfc3dda6d8a07e449fdd29 <br/>
英文原文:A Brief History of Random Numbershtml

转载请注明出处,保留原文连接以及做者信息前端


(罗马 12mm 骰子,大英博物馆便携式文物保护方案-CC BY-SA 2.0)java

“在全部的产生随机数的事物中,我认为没有什么可以超越骰子了”,这是统计学家 Francis Galton 在 1890 年的《天然》杂志中写道。它们在容器中不断地翻滚、互相撞击,以各类形式和角度与容器壁发生碰撞,在容器中的位置和形态在外界看来都是那么不可预知,容器哪怕只发生一次晃动,外界都不可能知道里面究竟是什么形态。react

古已有之的随机数

到底如何才能生成均匀的随机数列呢?天然界中随机性大量而近乎完美的存在,人类并不能准确地预知和量化这种随机性。迄今为止发现最先的骰子(4 个面)是来自中东的一座公元前 24 世纪的坟墓里。再近一些的历史是在公元前 1100 年的中国,利用火烧龟壳产生的随机龟裂现象,一些“先知”会根据龟裂状况来对将来作判断。又过了几个世纪,在中国诞生了易经占卜法,利用 49 蓍草法进行占卜,其操做的分裂过程很相似于抛硬币。git

机器生成随机数的第一次触碰

(摘自:“ A Million Random Digits with 100,000 Normal Deviates”)github

时间到了 20 世纪 40 年代中期,现代世界须要更多的随机数,再也不是骰子或者蓍草能够知足的了。RAND 公司发明了一种机器,经过随机脉冲发生器能够生成大量的随机数。他们将这个机器运行所产生的数字聚合起来并发布成图书“A Million Random Digits with 100,000 Normal Deviates”。这在如今看来是十分荒谬的,可是在当时倒是一个突破。这是人类第一次产生如此大量的、高质量的随机数,而且对公众是开放的。这本书 RAND 公司一直印刷到了 2001 年,如今在亚马逊上也能够看获得web

于此相似的机器:摇奖机,是由著名的 Bletchley Park WWII 破译小组在 20 世纪 40 年代发明的,当时被用来生成英国保险债券彩票所使用的随机数。为了平息公众对摇奖机的公平性和准确性的质疑和担忧,官方斥资制做了当时的巨型纪录片:“摇奖机的重要性(The Importance of Being E.R.N.I.E.)”。下面给出视频,很值得一看。算法


<iframe frameborder="0" width="640" height="498" src="https://v.qq.com/iframe/playe... allowfullscreen></iframe>

(The Importance of Being E.R.N.I.E.)编程

1951 年随机性终于被正式规范化而且整合到了计算机 Ferranti Mark 1 号中。Ferranti Mark 1 号内置了随机数生成指令,利用电气噪声能够一次性生成 20 个随机比特位。这一特性是由阿兰·图灵设计的。Christopher Strachey 利用这一特色,编写了一套随机情书生成器。下面这是情书例子,利用这个程序生成的 David Link 的 2009 复合计划

JEWEL LOVE
MY LIKING HUNGERS FOR YOUR ADORABLE INFATUATION.

YOU ARE MY EROTIC ARDOUR.: MY FOND RAPTURE. MY THIRST
SIGHS FOR YOUR INFATUATION. MY HEART SEDUCTIVELY WISHES YOUR
BREATHLESS LONGING.

YOURS CURIOUSLY

M. U. C.

(因为上面文字过于漏骨,译者尝试引伸出译文以下)

我对你的可爱迷恋至极。

你勾起了我全部对情爱的幻想。

我为你而狂热。

你的魅力使我对你充满了渴望。

个人心随你在而让我没法呼吸。

你的追求者

M.U.C

可是图灵的随机数指令几乎是当时的开发人员崩溃的,由于这种随机在自己就已经很不稳定的开发环境下又引入了不肯定性。人们但愿在软件中获得一致性的结果,可是用这种指令的软件永远不可能获得可重复的一致性结果,这也使得软件测试几乎变的不可行。

那么若是随机数生成器能够由一个肯定性的函数来替代会怎样呢?若是在给定一个肯定的初始条件,每次能够生成一样的随机序列会怎样呢?这就是伪随机数生成器(PRNG)。

伪随机数生成器(PRNG)

伪随机数生成器是由冯诺依曼在 1946 年创造的。他的基本思想是从一个随机数种子开始,对其平方,而后取中间值。接下来重复对获得的数取平方并取中间值的过程,就会获得一个具备统计意义属性的随机数序列了。这也就是广为人知的平方取中法

然而,冯诺依曼的方法并无经得住时间的考验,由于不论从什么随机种子开始,序列最终都会落入某个短循环序列,好比:8100,6100,4100,8100,6100,4100……。

序列中的数字是依赖于前一个数字的这种生成函数,上面的重复循环问题是不可避免的。可是若是说这个循环间隔很是很是大,对实际应用并不会产生影响,那会怎样呢?

1949 年,数学家 D.H.Lehmer 利用线性同余生成器(LCG)实现了这一思路。下面给出的是基于 Lehmer 的方法所实现的一种朴素 PRNG,叫作中央随机数生成器,使用 JavaScript 在 1995 年写的。

// The Central Randomizer 1.3 (C) 1997 by Paul Houle (paul@honeylocust.com)
    // See:  http://www.honeylocust.com/javascript/randomizer.html
    rnd.today=new Date();
    rnd.seed=rnd.today.getTime();
    function rnd() {
      rnd.seed = (rnd.seed*9301+49297) % 233280;
      return rnd.seed/(233280.0);
    };
    
    function rand(number) {
      return Math.ceil(rnd()*number);
    };

注意代码中的魔法数字(如 9301 等),这些数字(一般是质数)是用来最大化重复区间的——上面所提到的自我重复的循环区间。这种 PRNG 使用当前时间做为种子值,重复区间能够达到 2 的 31 次方。

这种中央随机生成器发明之初很是流行,由于那时的 JavaScript 1.0 尚未内置 Math.random() 函数,当时的 Web 1.0 环境下,你们都想让本身的 banner 广告随机旋转。一个开发者 Paul Houle 说道:“它在不少状况下已经很好用了,可是不能使用它来作保密使用”。

对 PRNG 的更高要求

互联网确实须要保密。SSL 诞生在 1995 年,它的加密方案须要高质量的 PRNG。它的发展也直接致使了一段时间的 PRNG 野蛮创新时期。若是你回头看一下全部的随机数生成器的专利,你可能会感觉到就像现代版的第一次制造飞机的浪潮同样。

20 世纪 90 年代中期的 CPU 是没有内置随机数生成指令的,这使得那时候好的随机种子特别可贵。原本这问题也不大,不过当飞利浦的 Hallam-Baker 发现 Netscape(当时市场上的巨头)的 SSL web 服务器使用了“当前时间 + 一组特殊 ID”组合做为种子的时候,这个问题变成了一个切身体会到的安全问题了。Hallam-Baker 展现了一个攻击者很容易猜到种子值,而且对他们所拿到的服务器流量进行解密的过程。猜种子值是一个很是常规的攻击手段,尽管这种手法如今变得愈来愈困难。这里给出 2009 年在 Hacker News 上的一段很是经典的攻击演练

到了 1997 年,计算机科学家们厌倦了生成随机数所受限的条件,来自 SGI 的一个团队发明了 LavaRand,它是用一个网络摄像头来对着熔岩灯拍照。从摄像头中过来的图片数据是一个真实的熵源——像图灵那样的真实随机数生成器(TRNG)——能够以 165kb/s 的速率生成随机数。一如当时硅谷的风格,熔岩灯平台很快拿到了专利

AutoDesk 的创始人 John Walker 在全世界范围内推广他的 HotBits,这是一种“随机数即服务”的应用,背后原理是盖革计数器来保证其量子随机性。1998 年成立的 Random.org 为互联网提供真正的随机数。他们提供的服务包括真正的抛硬币随机、骰子随机和卡牌洗牌随机等。

上面所提到的大多数算法后来都无人问津了,可是一个叫作梅森旋转随机数生成器(The Mersenne Twister)的软件 PRNG 鹤立鸡群,它是由松本真(Makoto Matsumoto)和西村 拓士(Takuji Nishimura)在 1997 年发明的。它完美地平衡了性能和随机数的质量,而且经受住了时间的考验。其基本思想是基于线性反馈移位寄存器(LFSR),产生一个循环周期很是长的肯定性序列,循环周期可以达到 2¹⁹⁹³⁷− 1。在当前的编程语言中,这种算法依旧是默认的 PRNG。

在 1999 年,随机数市场发生了一个巨大的变化,Intel 在其 i810 芯片组上集成了芯片级的随机数生成器。这样使得新的服务器都自带热噪声的本地源随机数生成能力——真正的随机数生成器(TRNG)。这很伟大,可是它始终没有软件 PRNG 快,因此加密软件依旧不得不依赖于伪随机数生成器(PRNG)。

这就把咱们带到了“密码安全 PRNG”(CSPRNG)(这些讨厌的缩写!难怪不少人认为计算机科学很烦人)。CSPRNG 对于 SSL 特别重要。那么 CSPRNG 的原理是什么呢?这里有一份 131 页的论文来介绍 CSPRNG。祝你在里面阅读愉快。

不言而喻,CSPRNG 是一个强需求。梅森旋转随机数生成器并非一种 CSPRNG,由于若是能够给定大量的先前序列样本,后面的数字是能够预计的出来。

时间再拉近一些,2012 年,Intel 为 TRNG 增长了 RDRANDRDSEED 指令,具备 500MB/s 的生产效率。可是 RDRAND 的完整性一直被质疑,里面是否是有某些缺陷?或者是为美国国家安全局内置了什么东西?没人确切地知道这个问题的答案,我猜某些地方的某些人必定知道,但是他们也必定不会公开。

开源硬件随机数生成器


(由一种硬件随机数生成器 PEDOUBLER 生成的随机数据)

近些年开源硬件 TRNG 也逐渐崭露锋芒。它们广受欢迎得益于其设计的透明化:你能够本身构建线路,也能够用现有的组件搭建。彻底的透明化使得对硬件随机数生成没有任何的担忧和疑虑。REDOUBLER无限噪声 TRNG是两个开源硬件随机数生成器,连接中给出他们的 Github 源码地址。

结尾

今天,依旧有关于对随机数生成方法选择的争论,在操做系统内核、编程语言和安全包(如 OpenSSL 或者 OpenSSH)方面均未中止。有许多不一样的算法聚焦于不一样的特色上,如速度、占用空间、安全性等方面,也有一些安全专家依旧在寻找攻破已有算法的方法。可是对于咱们平常的使用来说,在大多数的操做系统中你能够放心地使用 /dev/random,或者编程语言中你能够随心地使用 rand() 函数,都能给你带来很好的使用体验,而且你这么作,阿兰·图灵也会很开心。

欢迎你们关注个人前端大哈 - 知乎专栏,按期发布高质量前端文章。


我最近正在写一本《React.js 小书》,对 React.js 感兴趣的童鞋,欢迎指点

相关文章
相关标签/搜索