1. 程式人生 > >Proof of work

Proof of work

起源

工作量證明(Proof Of Work,簡稱POW),簡單理解就是一份證明,用來確認你做過一定量的工作。監測工作的整個過程通常是極為低效的,而通過對工作的結果進行認證來證明完成了相應的工作量,則是一種非常高效的方式。比如現實生活中的畢業證、駕駛證等等,也是通過檢驗結果的方式(通過相關的考試)所取得的證明。

工作量證明系統(或者說協議、函式),是一種應對拒絕服務攻擊和其他服務濫用的經濟對策。它要求發起者進行一定量的運算,也就意味著需要消耗計算機一定的時間。這個概念由Cynthia Dwork 和Moni Naor 1993年在學術論文中首次提出。而工作量證明(POW)這個名詞,則是在1999年 Markus Jakobsson 和Ari Juels的文章中才被真正提出。


雜湊現金是一種工作量證明機制,它是亞當·貝克(Adam Back)在1997年發明的,用於抵抗郵件的拒絕服務攻擊及垃圾郵件閘道器濫用。在比特幣之前,雜湊現金被用於垃圾郵件的過濾,也被微軟用於hotmail/exchange/outlook等產品中(微軟使用一種與雜湊現金不相容的格式並將之命名為電子郵戳)。

雜湊現金也被哈爾·芬尼以可重複使用的工作量證明(RPOW)的形式用於一種比特幣之前的加密貨幣實驗中。另外,戴偉的B-money、尼克·薩博的位元金(Bit-Gold)這些比特幣的先行者,都是在雜湊現金的框架下進行挖礦的。

2
雜湊函式

雜湊函式(Hash Function),也稱為雜湊函式,給定一個輸入x,它會算出相應的輸出H(x)。雜湊函式的主要特徵是:

輸入x可以是任意長度的字串

輸出結果即H(x)的長度是固定的

計算H(x)的過程是高效的(對於長度為n的字串x,計算出H(x)的時間複雜度應為O(n))

而對於比特幣這種加密系統所使用的雜湊函式,它需要另外具備以下的性質:

免碰撞,即不會出現輸入x≠y,但是H(x)=H(y)

其實這個特點在理論上並不成立,比如,比特幣使用的SHA256演算法,會有2^256種輸出,如果我們進行2^256+1次輸入,那麼必然會產生一次碰撞;甚至從概率的角度看,進行2^130次輸入就會有99%的可能發生一次碰撞。不過我們可以計算一下,假設一臺計算機以每秒10000次的速度進行雜湊運算,要經過10^27年才能完成2^128次雜湊!甚至可以這麼說,即便是人類製造的所有計算機自宇宙誕生開始一直運算到今天,發現碰撞的機率也是極其小的。


隱匿性,也就是說,對於一個給定的輸出結果H(x),想要逆推出輸入x,在計算上是不可能的。

不存在比窮舉更好的方法,可以使雜湊結果H(x)落在特定的範圍。

以上特點是比特幣的工作量證明系統可以正常執行的基石。

3
工作量證明的基本原理

工作量證明系統主要特徵是客戶端需要做一定難度的工作得出一個結果,驗證方卻很容易通過結果來檢查出客戶端是不是做了相應的工作。這種方案的一個核心特徵是不對稱性:工作對於請求方是適中的,對於驗證方則是易於驗證的。它與驗證碼不同,驗證碼的設計出發點是易於被人類解決而不易被計算機解決。
下圖表示的是工作量證明的流程:


舉個例子,給定的一個基本的字串"Hello, world!",我們給出的工作量要求是,可以在這個字串後面新增一個叫做nonce的整數值,對變更後(新增nonce)的字串進行SHA256雜湊運算,如果得到的雜湊結果(以16進位制的形式表示)是以"0000"開頭的,則驗證通過。為了達到這個工作量證明的目標。我們需要不停的遞增nonce值,對得到的新字串進行SHA256雜湊運算。按照這個規則,我們需要經過4251次計算才能找到恰好前4位為0的雜湊雜湊。

"Hello, world!0" => 1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64
"Hello, world!1" => e9afc424b79e4f6ab42d99c81156d3a17228d6e1eef4139be78e948a9332a7d8
"Hello, world!2" => ae37343a357a8297591625e7134cbea22f5928be8ca2a32aa475cf05fd4266b7
...
"Hello, world!4248" => 6e110d98b388e77e9c6f042ac6b497cec46660deef75a55ebc7cfdf65cc0b965
"Hello, world!4249" => c004190b822f1669cac8dc37e761cb73652e7832fb814565702245cf26ebb9e6
"Hello, world!4250" => 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9

通過這個示例我們對工作量證明機制有了一個初步的理解。有的人會認為如果工作量證明只是這樣的一個過程,那是不是隻需要記住nonce為4521計算能通過驗證就行了?當然不是的,這只是一個個例。

下面,我們將輸入簡單的變更為"Hello, world+整數值",整數值取1到1000,也就是說,將輸入變成一個由1000個值組成的陣列:"Hello, world!1、Hello, world!2……Hello, world!1000"。然後對陣列中的每一個輸入依次進行上面例子中要求的工作量證明——找到前導為4個0的雜湊雜湊。

容易算出,預期大概要進行2^16次嘗試(雜湊值的偽隨機特性使得我們可以做概率估算),才能得到4個前導0的雜湊雜湊。而統計一下剛才進行的1000次計算的實際計算結果,我們會發現,進行計算的平均次數為66958次,十分接近2^16(65536)。在這個例子中,數學期望的計算次數,就是我們要求的“工作量”,重複多次進行的工作量證明會是一個符合統計學規律的概率事件。
統計輸入的字串與對應得到目標結果實際使用的計算次數列表如下:

Hello, world!1 => 42153
Hello, world!2 => 2643
Hello, world!3 => 32825
Hello, world!4 => 250
Hello, world!5 => 7300
...
Hello, world!995 => 164819
Hello, world!996 => 178486
Hello, world!997 => 22798
Hello, world!998 => 68868
Hello, world!999 => 46821

比特幣體系裡的工作量證明機制與上述示例類似,但要比它更復雜一些。

4
比特幣中的工作量證明

比特幣網路中任何一個節點,如果想生成一個新的區塊並寫入區塊鏈,必須解出比特幣網路出的工作量證明的迷題。這道題關鍵的三個要素是工作量證明函式、區塊及難度值。工作量證明函式是這道題的計算方法,區塊決定了這道題的輸入資料,難度值決定了這道題的所需要的計算量。
1.工作量證明函式

和我們上節例子中用到的雜湊函式一樣,比特幣系統中使用的工作量證明函正是SHA256。

SHA是安全雜湊演算法(Secure Hash Algorithm)的縮寫,是一個密碼雜湊函式家族。這一組函式是由美國國家安全域性(NSA)設計,美國國家標準與技術研究院(NIST) 釋出的,主要適用於數字簽名標準。SHA256就是這個函式家族中的一個,是輸出值為256位的雜湊演算法。到目前為止,還沒有出現對SHA256演算法的有效攻擊。
2.區塊

比特幣的區塊由區塊頭及該區塊所包含的交易列表組成。區塊頭的大小為80位元組,由4位元組的版本號、32位元組的上一個區塊的雜湊值、32位元組的Merkle Root Hash、4位元組的時間綴(當前時間)、4位元組的當前難度值、4位元組的隨機陣列成。區塊包含的交易列表則附加在區塊頭後面,其中的第一筆交易是coinbase交易,這是一筆為了讓礦工獲得獎勵及手續費的特殊交易。

區塊的大致結構如圖所示:


擁有80位元組固定長度的區塊頭,就是用於比特幣工作量證明的輸入字串。因此,為了使區塊頭能體現區塊所包含的所有交易,在區塊的構造過程中,需要將該區塊要包含的交易列表,通過Merkle Tree演算法生成Merkle Root Hash,並以此作為交易列表的摘要存到區塊頭中。其中Merkle Tree的演算法圖解如下:



3.難度值

難度值(difficulty)是礦工們在挖礦時候的重要參考指標,它決定了礦工大約需要經過多少次雜湊運算才能產生一個合法的區塊。比特幣的區塊大約每10分鐘生成一個,如果要在不同的全網算力條件下,新區塊的產生保持都基本這個速率,難度值必須根據全網算力的變化進行調整。簡單地說,難度值被設定在無論挖礦能力如何,新區塊產生速率都保持在10分鐘一個。

難度的調整是在每個完整節點中獨立自動發生的。每2016個區塊,所有節點都會按統一的公式自動調整難度,這個公式是由最新2016個區塊的花費時長與期望時長(期望時長為20160分鐘即兩週,是按每10分鐘一個區塊的產生速率計算出的總時長)比較得出的,根據實際時長與期望時長的比值,進行相應調整(或變難或變易)。也就是說,如果區塊產生的速率比10分鐘快則增加難度,比10分鐘慢則降低難度。

這個公式可以總結為如下形式:

新難度值 = 舊難度值 * ( 過去2016個區塊花費時長 / 20160 分鐘 )

工作量證明需要有一個目標值。比特幣工作量證明的目標值(Target)的計算公式如下:

目標值 = 最大目標值 / 難度值

其中最大目標值為一個恆定值:
0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

目標值的大小與難度值成反比。比特幣工作量證明的達成就是礦工計算出來的區塊雜湊值必須小於目標值。

與第3節所舉的例子相類比,我們也可以簡單理解成,比特幣工作量證明的過程,就是通過不停的變換區塊頭(即嘗試不同的nouce值)作為輸入進行SHA256雜湊運算,找出一個特定格式雜湊值的過程(即要求有一定數量的前導0)。而要求的前導0的個數越多,代表難度越大。

4.工作量證明的過程

我們可以把比特幣礦工解這道工作量證明迷題的步驟大致歸納如下:

生成Coinbase交易,並與其他所有準備打包進區塊的交易組成交易列表,通過Merkle Tree演算法生成Merkle Root Hash

把Merkle Root Hash及其他相關欄位組裝成區塊頭,將區塊頭的80位元組資料(Block Header)作為工作量證明的輸入

不停的變更區塊頭中的隨機數即nonce的數值,並對每次變更後的的區塊頭做雙重SHA256運算(即SHA256(SHA256(Block_Header))),將結果值與當前網路的目標值做對比,如果小於目標值,則解題成功,工作量證明完成。

該過程可以用下圖表示:


5
結語

比特幣的工作量證明,就是我們俗稱“挖礦”所做的主要工作。理解工作量證明機制,將為我們進一步理解比特幣區塊鏈的共識機制奠定基礎。在之後的文章中,我們將會詳細介紹比特幣交易和區塊的結構及同步過程、最長鏈機制以及達成共識的原理。