接上文:
談及挖礦,首選浮現在腦海中的應該是:
但區塊鏈中的挖礦其實這樣的:
機架上排滿礦機,不停地在做運算,而且是是在做Hash運算。有人稱這種挖礦爲能源黑產,把電能轉化爲數字貨幣。那我們今天就來談談Hash算法和POW共識算法的關係。
01 Hash算法
談及Hash,我們要區分普通的Hash算法和密碼學中的Hash算法。
普通的Hash算法,一般也稱之爲散列表或哈希表,屬於一種基本的數據結構。一般用於實現O(1)的查詢條件之中, 涉及哈希函數的選取和解決哈希碰撞問題。
它的應用十分廣泛,像C++標準庫中的hashmap, Java中的HashMap,Python中的dict,都採用Hash算法實現。另外想很多緩存產品, memecached, redis都是hash算法的大規模應用。
而密碼學中的Hash算法,可以用一個公式來描述:
摘要/散列值/指紋 = hash(消息)
算法的輸入是消息,或者一堆二進制內容。最終輸出的是固定長度的一個二進制串,可稱之爲摘要,散列值,指紋等。hash算法也有很多種。密碼學的hash算法有五大重要特徵:
-
消息是輸入相同,輸出值相同,而且所有的輸出都是等長;
-
不管輸入多長,運算速度快;
-
算法具備單向性,極難通過輸出值獲取輸入值;
-
輸入信息一旦被修改,即使很輕微的修改,輸出值也不一樣;
-
不存在hash碰撞。也就是很難找到兩個不同的消息,他們的輸出值是一樣的;
密碼學Hash算法很多,比如MD4, SHA。但MD5被中國的王小云教授證明是不安全的,所以目前使用廣泛的是SHA族類算法。比特幣中使用的是SHA-256算法。
我們可以演示一下Python中使用SHA-256的過程:
% python
Python 3.7.3 (default, Nov 15 2019, 04:04:52)
>>> import hashlib
>>> hashlib.sha256("hello world!".encode('utf-8')).hexdigest()
'7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'
>>> hashlib.sha256("hello world".encode('utf-8')).hexdigest()
'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
>>> hashlib.sha256("hello world, bitcoin ethereum consusus".encode('utf-8')).hexdigest()
'39a0a566f63869830e769533c4efabd31cba7cf624cd23e67638a25354fa5c10'
密碼學的Hash算法的特性決定了它的應用範圍,經常被用於身份驗證,文件指紋,消息防篡改等各個方面。
下面,我們講跟區塊鏈極其相關的一種應用,HashCash。
02 HashCash
HashCash我們在文章《從區塊技術的發展歷史看區塊鏈是什麼?》中提到,由Adam Back設計,具體論文見:http://www.hashcash.org/papers/hashcash.pdf。Adam Back在今天的區塊鏈行業仍然具有巨大的影響力。他是Blockstream公司的創始人和CEO,比特幣核心開發者大部分都是Blockstream公司的僱員。
HashCash最早出現是爲了解決網絡中的資源被大量濫用,特別是垃圾郵件氾濫。怎麼辦呢?
HashCash的思路很簡單,在發郵件前能不能先乾點小活兒,做對了我才接收你的郵件。這個活兒不能太重,但至少要佔用發送方的一些資源。
這個流程其實大家應該很熟悉:
12306佔用的是人的注意力,HashCash是CPU的算力,他的方式是:
-
在電子郵件的消息頭中,增加一個 hashcash 戳記(hashcash stamp)散列值;
-
該散列中包含收件人地址,發送時間,salt,該散列值特別之處在於它至少前20位必須是0纔是一個合法的hashcash戳記
-
爲了得到合法的散列值,發送者必須經過許多次嘗試(改變salt值)才能獲得。
HashCash背後的設計思路就是希望基於的數學難題,希望你做一些的工作,也就是付出CPU的計算代價(這個概念很重要,比特幣中這個也是關鍵),得到正確的結果,才能獲取某些資源(比方說往你的郵箱發送垃圾郵件)。
Hash算法速度相對快,輸入數據相差一點點,都會導致散列值千差萬別的特性,被Adam Back選中。用cash代表付出算力之後的資源回報,用詞非常精當,特別延用到比特幣中作爲POW共識算法的核心,才合適不過。
03 比特幣挖礦
以比特幣爲代表的區塊鏈技術稱之爲分佈式賬本。既然是賬本,就存在非常核心的問題,賬房先生在哪裏?誰來負責記賬呢?
在傳統的中心化應用中,處理這個問題很簡單,在應用的賬戶系統系統裏面,設置不同的權限即可,把這種核心權限賦予極少部分的人來處理。
但比特幣是一個純粹的P2P系統,每個節點的權限和地位都是一樣的,相當於很多人要一起決策一件事情,這個過程在區塊鏈裏面稱之爲共識(Consensus),共識的機制也就成稱之爲共識算法。
中本聰在設計比特幣算法的時候,受到HashCash的啓發,採取工作量證明的方式來實現記賬過程,參與記賬的節點,稱之爲礦工。工作量證明在比特幣白皮書中明確提到,具體見:
https://github.com/ConsensusDev/whitepaper/blob/master/bitcoin.md(整理了各種版本),有詳細的描述。
礦工合併收到的交易形成一個完整的區塊,區塊頭由一些字段構成,其中最後一個字段nonce是可變的,礦工不斷修改nonce的值,並計算整個區塊頭的hash值,當hash值小於某個目標值的時候,纔算記賬成功,本區塊是一個合法區塊,廣播到全網,礦工獲得記賬獎勵。目標值跟難度值相關聯。難度值越大,目標值越小(hash值前面的0越多),挖礦難度越高。
核心尋找nonce的過程類似於下面一段代碼:
def proof_of_work(header, difficulty_bits):
# calculate the difficulty target
target = 2 ** (256-difficulty_bits)
for nonce in xrange(max_nonce):
hash_result = hashlib.sha256(str(header)+str(nonce)).hexdigest()
# check if this is a valid result, below the target
if long(hash_result, 16) < target:
print "Success with nonce %d" % nonce
print "Hash is %s" % hash_result
return (hash_result,nonce)
print "Failed after %d (max_nonce) tries" % nonce
return nonce
完整的代碼見:
https://github.com/ConsensusDev/code/blob/master/pow/proof_of_work.py
運算難度隨難度的增加指數增加,筆者電腦爲2018年款的macbook,截取一些運算結果如下:
Difficulty: 1048576 (20 bits)
Starting search...
Success with nonce 237723
Hash is 000005720acd8c7207cbf495e85733f196feb1e3692405bea0ee864104039350
Elapsed Time: 0.5485 seconds
Hashing Power: 433381 hashes per second
Difficulty: 2097152 (21 bits)
Starting search...
Success with nonce 687438
Hash is 000003a6eeee97491a9183e4c57458172edb6f9466377bf44afbd74e410f6eef
Elapsed Time: 1.5282 seconds
Hashing Power: 449829 hashes per second
Difficulty: 4194304 (22 bits)
Starting search...
Success with nonce 1759164
Hash is 0000008bb8f0e731f0496b8e530da984e85fb3cd2bd81882fe8ba3610b6cefc3
Elapsed Time: 3.9695 seconds
Hashing Power: 443166 hashes per second
Difficulty: 8388608 (23 bits)
Starting search...
Success with nonce 14214729
Hash is 000001408cf12dbd20fcba6372a223e098d58786c6ff93488a9f74f5df4df0a3
Elapsed Time: 32.6874 seconds
Hashing Power: 434868 hashes per second
Difficulty: 16777216 (24 bits)
Starting search...
Success with nonce 24586379
Hash is 0000002c3d6b370fccd699708d1b7cb4a94388595171366b944d68b2acce8b95
Elapsed Time: 55.3770 seconds
Hashing Power: 443981 hashes per second
我們這裏只闡述了核心的挖礦過程,更詳細的流程描述可以見:《精通比特幣》一書。隨着比特幣價格的一路走高,越來越多的礦工加入算力軍備競賽,目前整個算力也達到恐怖的110.18 EH/s。比特幣網絡本身隨着算力的變化,動態調整難度值。比特幣網絡的運行10年的難度曲線如下:
當然比特幣網絡也是這場算力競爭中最大的收益者,算力越大,系統越安全,越能形成最大的共識,因而讓比特幣的市值長期超過整個數字貨幣市場的50%。
密碼學Hash算法在區塊鏈技術中運用廣泛,除了挖礦,在區塊打包中也大放異彩,區塊鏈不可篡改的算法保障就是Hash算法決定的。下次探討這個問題,敬請期待。