比特幣原理詳解

東大大資料組Zzzcg發表於2019-10-29

一、什麼是比特幣

比特幣是一種電子貨幣,是一種基於密碼學的貨幣,在2008年11月1日由中本聰發表比特幣白皮書,文中提出了一種去中心化的電子記賬系統,我們平時的電子現金是銀行來記賬,因為銀行的背後是國家信用。去中心化電子記賬系統是參與者共同記賬。比特幣可以防止主權危機、信用風險。其好處不多做贅述,這一層面介紹的文章很多,本文主要從更深層的技術原理角度進行介紹。

二、問題引入

 假設現有4個人分別稱之為ABCD,他們之間發起了3個交易,A轉給B10個比特幣,B轉給C5個比特幣,C轉給D2個比特幣。如果是傳統的記賬方式,這些交易會記錄在銀行的系統中,這些資訊由銀行來記錄,我們相信銀行不會隨意新增、刪除或修改一條交易記錄,我們也不會關注到底有哪些交易,我們只關注自己的賬戶餘額。而比特幣的記賬方式為ABCD每個人儲存了這樣一份賬本,賬本上記錄了上述交易內容,如果每個人賬本實時的一致,ABCD就不再需要銀行。
        比特幣是這樣做的,每當有人發起一筆交易,他就要將一筆交易廣播至全網,由全網中的某一個人,把一段時間內的交易打包好記錄到一個區塊上,再按照順序把這些區塊,一個一個的連結在一起,進而形成了一個鏈條,這就是所謂的區塊鏈。

 

那麼問題來了

1、我憑什麼要參與這個系統,我為什麼要動用自己的計算機資源來儲存這些資訊呢?

2、以誰的記錄為準呢?比如上面的賬單順序,A使用者可能是這個順序,但是B可能順序不一樣,甚至可能B根本就沒有接收到C給D轉賬的這個訊息。

3、比特幣如果做到支付功能,保證該是誰的錢就是誰的錢,而且只有其所有者才能花。

4、如何防偽、防篡改以及雙重支付,防偽是驗證每條交易的真的是某人發出的,比如B可能杜撰一條訊息,說某某給我轉了一筆錢,這就是一個假訊息,或者B說我給某人轉了多少錢,但是實際上他並沒有這麼多錢,又怎麼辦。防篡改指的是B可能想從區塊鏈上把自己曾經轉給某人錢的記錄刪掉,這樣他的餘額就會增加。雙重支付是指,B只有10比特幣,他同時向C和D轉10個比特幣,造成雙重花費。

三、為什麼要記賬?

因為記賬有獎勵,記賬有手續費的收益,而且打包區塊的人有系統獎勵,獎勵方案是,每十分鐘生成一個區塊,每生成一個區塊會獎勵一定數量的比特幣,最開始是50個BTC,過4年會獎勵25個BTC,再過4年再減少一半,以此類推。這樣比特幣的產生會越來越少,越來越趨近於一個最大值,計算公式是:50×6×24×365×4×(1+1/2+1/4+1/8+…)≈2100萬,其中最初獎勵50個比特幣,每小時有6個區塊,每天24小時,每年365天,前四年是如此,之後每四年減半。

此外,記賬獎勵還有每筆交易的小額手續費,每個交易發起都會附帶一定的手續費,這些手續費是給記賬的礦工的。

四、以誰為準?

各個節點通過工作量證明機制來爭奪記賬權,他們計算一個很複雜的數學題,第一個計算出來的節點就是下一個區塊的產生者。這個數學題很難,難到沒有一個人能同過腦子算出來,它是基於概率的方法,礦工必須通過遍歷、猜測和嘗試的辦法才能解開這個未知數。那麼這個數學難題到底是什麼呢?下面詳細介紹。

4.1雜湊函式

雜湊函式又稱為數字摘要或雜湊函式,它的特點是輸入一個字串,可以生成另外一個字串,但是如果輸入不同,輸出的字串就一定不同,而且通過輸出的字串,不能反推出輸入。舉個簡單的例子,對1-100內的數模10,可以認為是一種雜湊方法,比如98%10=8,66%10=6,98和66是輸入,模10是雜湊函式,8和6是輸出,在這個模型中,通過6和8無法推斷輸入是66和98,因為還可能是56和88等,當然因為這個例子比較簡單,所以會出現雜湊碰撞,即66和56的結果都是6,輸出的結果相同。一個優秀的雜湊函式,可以做到輸出一定不同,雜湊碰撞的概率幾乎為0。常見的雜湊函式有很多,比如MD系列和SHA系列等,比特幣採用的SHA256演算法,即輸入一個字串,輸出一個256位的二進位制數。下面是程式執行的結果。

通過程式結果可以看出,輸入的源資訊不同,得到的結果也不同(為了方便,結果用64位16進製表示),即使是orange多了一個句號,也會產生截然不同的結果。同時,通過輸出的十六進位制字串,也無法倒推出輸入。對於比特幣,只要瞭解SHA256的功能即可,如果感興趣可以深入瞭解SHA256的具體演算法。需要SHA256的C++原始碼留言郵箱或私信。

4.2挖礦原理

首先介紹一下比特幣每個區塊的資料結構,每個區塊由區塊頭和區塊體兩部分組成。

區塊體中包含了礦工蒐集的若干交易資訊,圖中假設有8個交易被收錄在區塊中,所有的交易生成一顆默克爾樹,默克爾樹是一種資料結構,它將葉子節點兩兩雜湊,生成上一層節點,上層節點再雜湊,生成上一層,直到最後生成一個樹根,稱之為默克爾樹根,只有樹根保留在區塊頭中,這樣可以節省區塊頭的空間,也便於交易的驗證。

區塊頭中包含父區塊的雜湊,版本號,當前時間戳,難度值,隨機數和上面提到的默克爾樹根。

 

 

假設區塊鏈已經連結到了某個塊,有ABCD四個節點已經蒐集了前十分鐘內全網中的一些交易資訊,他們選出其中約4k條交易,打包好,生成默克爾樹根,將區塊頭中的資訊,即發區塊雜湊+版本號+時間戳+難度值+隨機數+默克爾樹根組成一個字串str,通過兩次雜湊函式得出一個256的二進位制數,即SHA256(SHA256(str)) = 10010011……共256位,比特幣要求,生成的結果,前n位必須是0,n就是難度值,如果現在生成的二進位制數不符合要求,就必須改變隨機數的值,重新計算,只到算出滿足條件的結果為止。假設現在n是5,則生成的二進位制數必須是00000……(共256位)。一旦挖礦成功,礦工就可以廣播這個訊息到全網,其他的礦工就會基於該區塊繼續挖礦。下一個區塊頭中的父區塊雜湊值就是上一個區塊生成的00000……這個數。

解決這個數學難題要靠運氣,理論上,運氣最好的礦工可能1次雜湊就能算出結果,運氣差的可能永遠都算不出來。但是總體來看,如果一個礦工的算力越大,單位時間內進行的雜湊次數就越多,就越可能在短時間內挖礦成功。

那麼n是如何確定的呢?比特幣設計者希望,總體上平均每十分鐘產生一個區塊,總體上來看,挖礦成功的概率為1/2^n。現假設世界上有1W臺礦機,每臺礦機的算力是14T次/s = 1.4×10^13次/s,單位次/s稱之為雜湊率,10分鐘是600s,所以10分鐘可以做8×10^19次雜湊運算,從概率角度看,想要挖礦成功需要做2^n次運算,可以列出等式2^n = 8×10^19,可以解出n約為66。所以對於這種方法,我們沒有辦法使得自己的運氣變的更好,只能提高自己的算力,儘快的算出結果。

另外,需要模擬挖礦過程的C++程式碼可以回覆郵箱,程式碼可以通過調整難度值,模擬比特幣的挖礦演算法,控制區塊產生的速度。

五、如何防偽、防篡改、防雙重支付等問題

這部分是理解比特幣很重要的部分。

5.1電子簽名技術

身份認證技術在生活中很常見,可以是人臉識別、簽字、指紋等,但是這些方法在數字貨幣領域並不安全,因為它們一旦數字化,都可以通過複製的方法偽造。所以比特幣採用了電子簽名的方法。

註冊成為比特幣使用者時,系統會根據隨機數生成一個私鑰,私鑰會生成一個公鑰,公鑰又會生成一個地址,其中私鑰必須保密,可以儲存到硬碟裡或者記到腦子裡,因為這個私鑰是使用相應地址上的比特幣的唯一標識,一旦丟失,所有的比特幣將無法使用。下面介紹具體的轉換過程,不感興趣可以不看,只要知道隨機數->私鑰->公鑰->錢包地址這個過程,其中私鑰可以對一串字元進行加密,而公鑰可以對其進行解密,這就是非對稱加密,這類演算法總體上的功能都是一樣的,只是具體演算法有區別,由於這些演算法比較複雜,與SHA265演算法一樣不多做介紹,感興趣可以深入瞭解具體演算法,但是對於比特幣系統,只要瞭解其功能即可。典型的演算法是RSA,比特幣採用橢圓曲線加密演算法。

轉換過程(選讀,不影響理解)

    1、首先使用隨機數發生器生成一個私鑰,它是一個256位的二進位制數。私鑰是不能公開的,相當於銀行卡的密碼。

    2、私鑰經過SECP256K1演算法生成公鑰,SECP256K1是一種橢圓曲線加密演算法,功能和RSA演算法類似,通過一個已知的私鑰,生成一個公鑰,但是通過公鑰不能反推出私鑰。

    3、同SHA256演算法一樣,RIPEMD160也是一種HASH演算法,由公鑰可以得到公鑰的雜湊值,而通過雜湊值無法推出公鑰。

    4、將一個位元組的版本號連線到公鑰雜湊頭部,然後對其進行兩次SHA256運算,將結果的前4位元組作為公鑰雜湊的校驗值,連線在其尾部。

    5、將上一步的結果使用BASE58進行編碼,就得到了錢包地址(相當於銀行賬戶)。比如A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa

所以,通過以上的過程我們可以總結出私鑰、公鑰、錢包之間的關係如下圖。可以看到通過私鑰可以推出所有的值,公鑰雜湊和錢包地址之間可以通過BASE58和BASE58解碼演算法相互轉化。

瞭解了公鑰、私鑰、地址的概念後,防偽驗證的過程就很容易理解,當A發起一筆交易後,對訊息進行雜湊,生成數字摘要,對數字摘要,通過私鑰加密,生成一個密碼。之後A會廣播這個條交易訊息、公鑰以及密碼。收到訊息的人首先對交易資訊進行雜湊生成摘要1,再通過公鑰對密碼進行解密,生成摘要2,這樣,如果兩個摘要相同,說明這個訊息確實是A發出的。所謂的簽名,就是密文。

 

5.2餘額檢查

餘額的概念應該說根深蒂固,餘額是伴隨著稱之為借貸記賬法而產生的,也是目前銀行普遍採用的方法,將一個人的交易記錄統計好後算出一個餘額,但是在比特幣中沒有餘額這個概念,因為其採用的是UXTO模型的記賬方法。比如A->B10個比特幣,B->C5個比特幣,對於第二筆交易來說,B在發起這筆交易時要註明第一筆交易的資訊,這樣就可以知道B曾經從A那裡收到過10個比特幣,說明滿足第二筆交易發起的條件。所以比特幣中餘額的檢查是通過追溯的方法。

上圖描述了兩筆交易,交易10001中,B向C轉了10個比特幣,驗證這筆交易的過程是:首先將B的簽名通過B的公鑰解密,然後再和交易的具體內容(B簽名左側)對比,如果相同,說明訊息是B發出的,然後再檢查10000這個交易是否真的存在以及它的內容的真實性。這兩點都滿足了,就說明交易10001是可以被接受的,否則拒絕接受。

實際上,真實的交易比這個複雜的多,因為有可能是多筆交易構成了輸入,比如B->C20個比特幣,是由多筆交易A->B10,D->B10構成的,則前一筆交易ID就是兩個ID,甚至可能更多。這裡為了簡單描述,只列舉一筆交易。

5.3雙重支付

A同時發了兩條訊息,同時給B和C轉了10個比特幣,實際上他只有10個會怎麼樣?假設D節點先收到了轉給B10個BTC,然後收到了轉給C10個比特幣,通過上面的驗證方法,自然會拒絕後面的一個,與此同時,E節點可能先收到了轉給C10個BTC,然後收到了轉給B10個比特幣,他自然會拒絕後者。至於哪一筆交易最終會上鍊,就要看D和E哪個先解決難題,成功挖礦。

5.4防止篡改

假設A轉給B10個比特幣,但是他想把這個資訊從區塊鏈上刪除,這樣大家就都不知道這個事情存在,就可以賴賬。
        首先說一下最長鏈原則,假設某一個區塊後面有兩個礦工同時挖到了礦,或者由於網路延遲等原因產生了分歧,這時,各個節點先隨意根據自己認為對的區塊挖礦,只到下一個區塊產生,這時會有兩條鏈,但是有一條是長的,比特幣規定,以最長的鏈為準。如果某個節點仍然的固執的以較短的鏈為準,他就是在和大多數算力作對,這樣做的結果是,他挖的塊不被大家認可,會浪費時間和算力。

回到上面的場景,A想賴賬,就只能從記錄了A->B10個比特幣這個訊息的區塊的前一個區塊開始重新挖礦,造出一個支鏈來,但是實際上的區塊已經前進了很多,他只能不停的追趕,而且在追趕的同時,主鏈也在前進,他必須以比主鏈快的速度前進,如果他的算力足夠大,理論上通過較長的時間確實可以追趕成功,就實現了對交易資訊的篡改。然而其實這幾乎是不可能的,因為就算算力再大,平均出塊速度也是10分鐘,從非技術的角度講,一個人如果掌握了全網一半以上的算力,他為什麼不在主鏈上繼續挖礦呢?一個富可敵國的人應該不會甘願去做一個小偷吧。 

六、總結

區塊鏈並不等同於比特幣,比特幣也不是區塊鏈,區塊鏈只是比特幣應用的一種技術,這個技術能給我們帶來啟發,比特幣的偉大之處在於應用了前所未有的區塊鏈技術。區塊鏈技術還能在哪些方面應用還需繼續探索。

比特幣是區塊鏈技術最成功的應用,但是比特幣本身也有很多問題,它想通過發行貨幣來挑戰主權貨幣,這個動機有待商榷。此外,由於比特幣的匿名性,只需要一個公鑰或地址就能進行交易,為黑色產業提供了很好的平臺。另外,比特幣並不是一個成熟的支付系統,它具有吞吐率低,可擴充性差等缺點。

可能文字還是比較蒼白,可以看看李永樂老師講解的視訊,雖然沒有這個詳細,但是通俗易懂。

相關文章