天天看點

詳解POW工作量證明原理

     POW工作量證明(英文全稱為Proof of Work)早在比特币出現之前就已經有人探索,常見的是利用HASH運算的複雜度進行CPU運算實作工作量确定,當然你也可以利用卷積求導、大質數分解這些複雜的運算來達到工作量證明的目的(HASH隻是pow采用一種算法而已,你可以使用大部分需要疊代運算的算法實作POW,其實稍微改一下pow算法就有可能誕生一種山寨币,然後大肆宣傳欺騙小白,了解原理後就知道這并沒有什麼卵用),随着比特币成功後,POW為人們熟知,基于HASH的pow算法常被人誤解為是pow的代名詞,為了便于解釋pow原理本文還是采用HASH算法作為舉例。

定義

(Proof-of-work,工作量證明)最早是一個經濟學名詞,它是指系統為達到某一目标而設定的度量方法。簡單了解就是一份證明,用來确認你做過一定量的工作。監測工作的整個過程通常是極為低效的,而通過對工作的結果進行認證來證明完成了相應的工作量,則是一種非常高效的方式

在1999年,Markus Jakobsson and Ari Juels兩人将pow概念引入計算機體系,設計系統用以抵擋拒絕服務攻擊和網絡爬蟲,後來在反垃圾郵件中被廣泛使用。其設計理念是一個正常使用者寫一封郵件是需要一定的時間,而發送垃圾郵件者是無法接受這個等待的時間,如果pow系統能夠使垃圾郵件發送者需要更多的時間來發送郵件,就可以增大他們的成本,起到抵擋攻擊的作用。

pow系統中一定有兩個角色,工作者和驗證者,他們需要具有以下特點:

  • 工作者需要完成的工作必須有一定的量,這個量由工作驗證者給出。
  • 驗證者可以迅速的檢驗工作量是否達标。
  • 工作者無法自己"創造工作",必須由驗證者釋出工作。
  • 工作者無法找到很快完成工作的辦法。

pow曆史

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

哈希運算是一種最常見的工作量證明機制,它是亞當·貝克(Adam Back)在1997年發明的,用于抵抗郵件的拒絕服務攻擊及垃圾郵件網關濫用。在比特币之前,哈希現金被用于垃圾郵件的過濾,也被微軟用于hotmail/exchange/outlook等産品中(微軟使用一種與哈希現金不相容的格式并将之命名為電子郵戳)。

該機制主要利用HASH運算的複雜度,通過給定的初始值,通過簡單的值遞增規律,利用HASH碰撞原理,直到找到特定的碰值,可以通過調節碰撞值得長度,實作對于工作量的調節(碰撞值越長,所需要的運算量越大)

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

哈希現金掃盲

哈希現金HashCash是最典型的Solution-verification實作,HashCash也是目前應用最為廣泛的反垃圾郵件的pow系統。

在HashCash系統中,發件方向郵箱伺服器發送的郵件資訊中必須包含一段郵件簽名,郵件簽名中包含有收件人位址、發件時間和一個數字counter,counter需要使郵件簽名滿足條件:

利用SHA-1雜湊演算法對郵件簽名生成一個160-bit長度的哈希值,該哈希值前20位全為0 。此算法利用了雜湊演算法的不可預測性,SHA-1的碰撞機率決定了算法的安全性。

在目前的認知中,發件方除了窮舉嘗試,無法很快的找到滿足條件的簽名串。于是發件方在發送郵件之前的工作就是不斷地counter++生成新的郵件簽名,然後擷取SHA-1哈希值,判斷前20位是否全為0,如果不是的話重新生成。而對于郵件伺服器而言,隻需要做一次SHA-1判斷生成的簽名是否滿足條件即可,完全符合POW易于驗證的定義。

算法簡介

發送方簽名:
counter = 0;

while(1) {   
	result = SHA1(mailAdress + time + counter);   
	if (result.substring(0, 20) == "00000000000000000000") { 
	    break;   
	}   
	counter++; 
}
sig = mailAdress + time + counter;
           

服務端驗簽:

if (SHA1(sig).substring(0, 20) == "00000000000000000000") {
   return true;
}
           

散列函數如SHA-1是基本均勻分布的,對于我們生成的每一個郵件簽名來說,對應的的哈希值在每一位上出現0和1的機率應該是相同的,SHA-1生成的160-bit哈希結果,其所有的可能是 2^160 種,而前20位固定為0的情況有 2^140 種,是以每次生成的郵件簽名符合條件的機率為: 2^140 / 2^160 = 1/2^20

問題一,解空間必然存在,解空間的大小為2^140。

問題二,每一次生成郵件簽名命中的機率為 1/2^20 ,用戶端平均需要運算 2^20 次就能找到正确答案,運算時間為: PerSHA1Time*2^20 。

問題三,伺服器端需要丢棄掉已經出現過的答案,同時需要對收件人位址和時間戳做合法性校驗即可。

HASH POW原理

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

下圖表示的是工作量證明的流程:

詳解POW工作量證明原理

舉個例子,給定的一個基本的字元串"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的哈希散列。

容易算出,預期大概要進行216次嘗試(哈希值的僞随機特性使得我們可以做機率估算),才能得到4個前導0的哈希散列。而統計一下剛才進行的1000次計算的實際計算結果,我們會發現,進行計算的平均次數為66958次,十分接近216(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