區塊鏈是目前技術熱點之一,有人將它與互聯網媲美,也有人聲稱區塊鏈沒有未來。確定的是在大多數人對區塊鏈的理解仍停留在比特幣等加密數字貨幣概念的時候,已經有公司和個人嘗試將其應用於其它領域。若要對一個事物作出合理評價,較深入的了解必不可少,而了解的較快方式是從某個具體應用入手。現在最知名和“成功”的區塊鏈應用仍然是與它一同誕生的比特幣,網上不乏有比特幣的科普文,但是本人看來,這些文章要么寫得太抽象,要么寫得太通俗,看完之后能得到幾個概念,但若要深想下去還是一頭霧水。本篇是之前為公司培訓做的ppt整理而來,主要闡述了比特幣的核心概念,ppt面向公司全員,刪除程序員必備知識后整理成該博文。
注:本文旨在幫助大家理解比特幣[&區塊鏈],所以會有意簡化一些概念,即不保證描述和實際場景完全一致。關鍵點粗體顯示。
區塊鏈 = 鏈成一串的區塊集合
這肯定沒有異議吧,那么區塊里面包含什么呢?暫時可以認為包含如下東東:
重點關注散列值,它的身影貫穿區塊鏈始終。目前散列函數有很多種,以SHA256為例,輸出有2256種可能(培訓時費了老大勁讓大家對這個數的大小有個感性的認識)。散列函數的特點是不可逆,即給定一個散列值,推算出對應的輸入基本上是不可能的。這種特性讓它有了防篡改的功能,比如區塊被廣播並被其它節點確定后,若再去更改區塊里的其它字段(比如交易的比特幣金額,存於數據字段中),會造成新數據計算得到的散列值≠原散列值,那這個區塊一定是有問題的。我們用這種方式保障了區塊的安全/合法性。
目前區塊鏈典型應用之一知識產權保護的關鍵就是防篡改和相關度計算。
那么數據本身的安全呢?眾所周知,[公共]區塊鏈是匿名的,那么如何知道數據屬於誰,誰能存取該數據,這里就引出了密鑰的概念。
密鑰:用於加密和解密的一種規則
根據加密密鑰和解密密鑰是否相同,又可分為對稱加密和非對稱加密。各位對它們一定非常熟悉,它們在純粹加解密上的優缺點這里就不細說了,在效率上,前者一般都要高於后者。因此我們使用非對稱加密並非沖它的加密效果去,而是為了使用它“非對稱”這個特性帶來的好處,現實中有很多場景用到,比如調用第三方openapi,或者更復雜的oauth認證過程,調用方都會以私鑰簽名調用信息,服務方使用調用方的公鑰校驗調用者的合法性。這個特性使得匿名和去中心化成為可能,一次比特幣的交易可如下圖所示:
XX將1000B打入Bob的賬戶(即用Bob公鑰加密),Bob私鑰解密后取出
公鑰不需要含有任何Bob的個人信息,所以雖然其他人可以使用公鑰將數據綁定到這個“賬戶”,但也僅此而已,他們無法也無需知道這個公鑰到底是屬於誰的(除非公鑰所有人自己公開個人信息);只要有人能將之解出,那就表示那人有對應的私鑰,亦即他的身份是合法的(如果他將私鑰給了別人,那也無話可說)。於是,一個匿名的交易就完成了。
當然,上述圖示是非常不嚴謹的。首先,比特幣網絡是個閉環,Bob無法將比特幣取出(你見過比特幣長啥樣?),當然也無法主動存入,這類似於我們只能在ATM機上進行賬號間的轉賬操作,而不能取現;那Bob私鑰解密后的比特幣去哪了呢,或者說,本來這筆錢在“公鑰里”呆的好好的,取又取不出,你把它解出來干啥?答案是當Bob要將錢打入其他人的公鑰的時候,他就要用私鑰轉賬了;而之前XX轉給Bob亦是如此。所以更准確的圖示如下:
比特幣的交易鏈
現在讓我們看下比特幣中的加解密過程具體是怎樣的。
首先我們把交易給它結構化,可以簡單理解為:交易 = 我的錢轉給你 = 我的錢 + 轉給你。
由上圖可知:我的錢 = 我用私鑰解出的別人轉到我公鑰的錢 = 別人轉給公鑰的錢 + 我用私鑰解出;轉給你 = 轉多少到你的公鑰。
翻譯成數據結構,示例如下:
{ from: { 上一筆交易to數據的ID: "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18", key: 私鑰解密(用於證明我擁有上一筆交易轉出的錢) }, to: { 本筆輸出的ID: "8ae4538afc617cd284d36d135fe09f1a0d2f42a22d890d548f6f65cda45e6f1d2", 轉出多少錢: 0.01500000, lock: 公鑰加密(只有正確解密才能獲得轉出的錢) } }
我們將上述代碼的key和lock稱為腳本。lock和key可看作問題與答案,注意from中的key解密的是上一筆轉給我的交易的lock。比如XX轉了一筆錢給Bob,同時設置了lock:1+1=?——?是占位符,之后用key代替——等到Bob要花這筆錢時,他一定要提供正確的key值(此處是2),否則無法通過節點的交易校驗,同時Bob也要設置本筆交易的lock,以此類推。key與lock可以互換,只要合在一起等式成立即可。
將公私鑰代入腳本,可構建如下交易:
XX轉給Bob——
{ from: ……, to: { 本筆輸出的ID: "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18", 轉出多少錢: 10, lock: 轉入方的公鑰 } }
Bob轉給Alice——
{ from: { 上一筆交易to數據的ID: "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18", key: ? 解密 (私鑰加密(本次交易的散列值)后的密文)=本次交易的散列值 }, to: …… }
節點校驗Bob轉給Alice這筆交易,會將上一筆交易lock與當前交易key合並,此處即為:轉入方的公鑰解密 (私鑰加密(本次交易的散列值)后的密文)=本次交易的散列值。易得,若公私鑰是一對,那等式成立。
所謂節點,我們可以理解為日常聽說的比特幣礦工。他們無時無刻不在搜集交易,並將它們打包進區塊,這個過程就是“挖礦”。挖礦 = 新建有效區塊,具體過程如下:
- 交易校驗無誤后,節點將其放入本地的“未確認交易池”;
- 節點選取部分或全部未確認交易(一般選取佣金相對高的交易,佣金=from的金額-to的金額,可以自己找零調節,比如XX轉Bob10塊,Bob以此轉Alice8塊,轉自己即找零1.5塊,那么佣金為0.5塊),放入本地臨時區塊中;
- 計算該臨時區塊散列值。
如圖:
圖中上一個區塊的ID取的是區塊鏈中當前最末的有效區塊的ID。而計算得到散列值是剎那間的事,如果交易數據足夠多,那每秒都能產生萬億個區塊,如此,則吞吐量杠杠的。但是億萬個區塊承載的數據未必相同(根據節點自己的選擇而來),更不用說有同筆交易被多個節點打包的情況,為了賬本的一致性,我們需要避免鏈分支(分叉)的出現,能添加到鏈末尾的只能是其中一個區塊,即只能承認其中一個區塊是有效的。那么如何選出這個區塊,並讓其他節點心服口服呢,這就是共識算法需要解決的問題。
比特幣使用的共識算法是POW,proof of work,工作量證明。具體到實現,就是提高計算散列值這個環節的難度。怎么提高呢?
中本聰說,你算出的散列值一定要符合某種的規則,比如一定要是“9ce4538afc617cd284d361d53fe09f1a0d2f42a26d890d548f6f65cda45e6f1d2”這個數,如此,你的區塊就是可以被承認的。
此言一出,眾礦工紛紛吐槽:哇,中大神你懂不懂的,數據(交易)我都打包好了,出來的散列值還能變嗎?你說重新打包?選佣金低的試?求求你不要秀了。
中本聰說,行吧,給你們加個字段,該字段可隨意取數,汝等將其一並納入散列值計算中,該字段的值的改變勢必會影響到散列結果,如此,只要找到正確的隨機數,那么就能得到規定的結果,那么,區塊就可以被承認。
now,挖礦變成了:新建有效區塊 = 計算出符合規則的散列值 = 獲得一個使計算出的散列值符合規則的隨機數
規則為:
我們知道,2256是很大的一個數字, 要找到一個隨機數(為了覆蓋整個輸出值域,該隨機數也得是同量級位數),使得結果恰好等於其中之一,以目前計算機能力,到時光盡頭也未必能找到。所以說,這個規則定義的難度太大。
那么,我們制定一個難度不大的規則,如下:
只要散列結果落入特定區間即可,這個難度的量化不言自明:若紅色區間占滿整個橫條,那么難度是最低的,即得到的任意散列值都滿足條件,也就是剛開始沒有規則的狀態;如若占到一半,那么概率上講每兩次都有一次會成功,難度也不大;若調節到億分之一,那么概率上需要試錯一億次。也就是說,我們可以通過調節區間大小調節計算難度。比特幣目前是保持平均10分鍾出塊的速度,且會根據前幾次的出塊時間自動調節計算難度,而不至於由於硬件發展等因素導致速度的變化。另外,隨機數字節數也不用很大,比特幣中是4個字節。
在挖礦時,nonce隨機數是未知的,要從0試到232,但是這個數字其實不大,只有4294967296,以現在的礦機動輒14T每秒的算力,全部算完到上限也不需要一秒,肯定無法覆蓋難度對應的散列值域。所以我們需要使用創幣交易中的附帶信息,額外的字符串成為extra nonce,參看 比特幣挖礦究竟在計算一個什么問題?手動驗證區塊鏈給出答案。至於為什么是10分鍾,這個就見仁見智了,有人說考慮到網絡延時、帶寬,10分鍾是一個相對合適的時間,也有人覺得太長,比如LTC就是2.5分鍾。其實,這只是當初中本聰的一個設定,總要設置個時間嘛,只要不太短就行你說是不。
挖到礦后,節點需要將區塊入鏈。節點通過p2p向外廣播,其它節點收到后校驗區塊合法性,無誤后將該區塊存入自己的本地鏈,同時繼續向外廣播,並開啟下一輪挖礦競賽。通過p2p,所有節點的本地鏈都可以保持一致,這樣,去中心化就實現了。
值得討論的是,在新區塊發現到被網絡確認的時間段內,如果有多個節點同時找到有效的隨機數,或者節點收到其他多個節點的挖礦成功的消息,以哪個為准呢?答案是隨意,因為一般來說這種臨時分叉的情況會隨着后續區塊的挖掘自動消失,因為比特幣優先選擇鏈最長的那條分支,除非能保證各分支出塊的速率完全一樣,否則總會出現一定的時間差,從而導致其中一條分支變得更長成為主鏈,其余分支被網絡拋棄(也可能有惡意節點維持短分支,加大算力以圖在將來超過主鏈,這就涉及到51%攻擊了)。
康奈爾大學的研究人員Ittay Eyal和 Emin Gun Sirer發表的一篇論文里,描述了只要掌握25%算力即可成功攻擊比特幣網絡的場景,可參看 Selfish Mining: A 25% Attack Against the Bitcoin Network