做者:Alon Zakai
編譯:鬍子大哈 javascript
翻譯原文:huziketang.com/blog/posts/…
英文原文: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.)」。下面給出視頻,很值得一看。算法
(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)。
僞隨機數生成器是由馮諾依曼在 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 說道:「它在不少狀況下已經很好用了,可是不能使用它來作保密使用」。
互聯網確實須要保密。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 增長了 RDRAND
和 RDSEED
指令,具備 500MB/s 的生產效率。可是 RDRAND
的完整性一直被質疑,裏面是否是有某些缺陷?或者是爲美國國家安全局內置了什麼東西?沒人確切地知道這個問題的答案,我猜某些地方的某些人必定知道,但是他們也必定不會公開。
近些年開源硬件 TRNG 也逐漸嶄露鋒芒。它們廣受歡迎得益於其設計的透明化:你能夠本身構建線路,也能夠用現有的組件搭建。徹底的透明化使得對硬件隨機數生成沒有任何的擔憂和疑慮。REDOUBLER和無限噪聲 TRNG是兩個開源硬件隨機數生成器,連接中給出他們的 Github 源碼地址。
今天,依舊有關於對隨機數生成方法選擇的爭論,在操做系統內核、編程語言和安全包(如 OpenSSL 或者 OpenSSH)方面均未中止。有許多不一樣的算法聚焦於不一樣的特色上,如速度、佔用空間、安全性等方面,也有一些安全專家依舊在尋找攻破已有算法的方法。可是對於咱們平常的使用來說,在大多數的操做系統中你能夠放心地使用 /dev/random
,或者編程語言中你能夠隨心地使用 rand()
函數,都能給你帶來很好的使用體驗,而且你這麼作,阿蘭·圖靈也會很開心。
歡迎你們關注個人前端大哈 - 知乎專欄,按期發佈高質量前端文章。
我最近正在寫一本《React.js 小書》,對 React.js 感興趣的童鞋,歡迎指點。