為什么比特幣可以防篡改
比特幣(Bitcoin)是一種加密貨幣,也是一種分布式的數(shù)字資產(chǎn),中本聰發(fā)布比特幣到今天已經(jīng)過去了 10 多年時間[^1],一些讀者可能接觸過區(qū)塊鏈技術,甚至投資過數(shù)字貨幣的資產(chǎn)。今天的區(qū)塊鏈總市值已經(jīng)達到了 2700 億美金,比特幣的市值也達到了 1700 億[^2],然而比特幣使用的底層技術其實非常簡單,它只是將這些技術巧妙地組合起來。
圖 1 - 比特幣
如果我們對比特幣等區(qū)塊鏈技術稍有了解,就會發(fā)現(xiàn)它是一個設計巧妙的分布式數(shù)據(jù)庫。作為在公網(wǎng)運行的分布式數(shù)據(jù)庫,比特幣和其它區(qū)塊鏈網(wǎng)絡都會面對網(wǎng)絡中的惡意節(jié)點的攻擊。因為比特幣需要面對復雜的網(wǎng)絡環(huán)境以及不可靠的節(jié)點,所以它在設計和實現(xiàn)上也做出了應對,我們可以看看它是如何組合現(xiàn)有的技術防止惡意節(jié)點對交易和賬戶數(shù)據(jù)進行篡改的。
比特幣網(wǎng)絡主要會通過以下兩種技術保證用戶簽發(fā)的交易和歷史上發(fā)生的交易不會被攻擊者篡改:
- 非對稱加密可以保證攻擊者無法偽造賬戶所有者的簽名;
- 共識算法可以保證網(wǎng)絡中的歷史交易不會被攻擊者替換;
非對稱加密
非對稱加密算法[^3]是目前廣泛應用的加密技術,TLS 證書和電子簽名等場景都使用了非對稱的加密算法保證安全。非對稱加密算法同時包含一個公鑰(Public Key)和一個私鑰(Secret Key),使用私鑰加密的數(shù)據(jù)只能用公鑰解密,而使用公鑰解密的數(shù)據(jù)也只能用私鑰解密。
asymmetric-cryptography
圖 2 - 非對稱加密特性
比特幣使用了非對稱加密算法保證每一筆交易的安全,網(wǎng)絡中的每一個賬戶(地址)都是一對秘鑰中的公鑰,賬戶的所有者會持有私鑰,下面就是一對剛剛生成的比特幣地址和私鑰[^4]:
- Address: 13RTT8MsbAj7o4zL7w4DNNuuwhgGgHqLnK
- Private Key: 469d998dd4db3dfdd411fa56574e52b6be318f993ca696cc5c683c45e8e147eb
需要注意的是,使用網(wǎng)站生成比特幣地址和私鑰是極其危險的做法,我們并不清楚網(wǎng)站是否會存儲私鑰,所以建議使用比特幣的客戶端生成公私鑰對。
任何人通過上面的地址 13RTT8MsbAj7o4zL7w4DNNuuwhgGgHqLnK 都可以向該賬號轉賬;賬號的持有者也可以使用私鑰簽名交易向其他地址轉賬,當我們想要向比特幣網(wǎng)絡中提交一筆新的交易時,需要先構建一個如下所示的交易結構:
- {
- "txid":"5be7a9e47f56c98e5297a44df52da0475f448ece98bb51489103cdf70653092f",
- "hash":"5be7a9e47f56c98e5297a44df52da0475f448ece98bb51489103cdf70653092f",
- "version":1,
- "size":224,
- "vsize":224,
- "locktime":0,
- "vin": [...],
- "vout": [...],
- "hex":"0100000001a90b4101e6cbb75e1ff885b6358264627581e9f96db9ae609acec98d72422067000000006b483045022100c42c89eb2b10aeefe27caea63f562837b20290f0a095bda39bec37f2651af56b02204ee4260e81e31947d9297e7e9e027a231f5a7ae5e21015aabfdbdb9c6bbcc76e0121025e6e9ba5111117d49cfca477b9a0a5fba1dfcd18ef91724bc963f709c52128c4ffffffff02a037a0000000000017a91477df4f8c95e3d35a414d7946362460d3844c2c3187e6f6030b000000001976a914aba7915d5964406e8a02c3202f1f8a4a63e95c1388ac00000000",
- "blockhash":"0000000000000000000c23ca00756364067ce5e815deb5982969df476bfc0b5c",
- "confirmations":5,
- "time":1521981077,
- "blocktime":1521981077
- }
接下來,我們可以使用持有的私鑰對整個交易中的全部字段進行簽名,然后將簽名與交易打包并發(fā)送到網(wǎng)絡中等待比特幣網(wǎng)絡的確認就可以了。
在比特幣的所有地址中,35hK24tcLEWcgNA4JxpvbkNkoAcDGqQPsP 地址中目前持有 250,000 多個 Bitcoin[^5],目前的市值大概為 20 億美元。在只知道地址的情況下,我們來算一下獲取該地址對應的私鑰需要多長時間。比特幣的私鑰總共有 256 位,即2256種可能。
目前我們沒有較為快捷的破解手段,只能使用暴力破解計算私鑰。假設我們使用 IBM 在 2018 年推出的超級計算機 Summit[^6],它能每秒能做1.4*107次浮點數(shù)計算,假設該計算機可以每秒計算相同次數(shù)的公私鑰對(計算公私鑰對遠比一次浮點數(shù)計算復雜),想要找到存放 20 億美元資產(chǎn)的地址對應的私鑰需要如下所示的時間:
我們整個宇宙的存在時間也只是破解該私鑰時間的幾十億分之一,所以在目前的計算能力沒有革命性突破的前提下,想要通過暴力破解的方式獲取公鑰對應的私鑰只有理論上的可能性,在實踐中是完全不可能的[^7]。
共識算法
MySQL 等數(shù)據(jù)庫以行為單位存儲數(shù)據(jù),而比特幣這個分布式數(shù)據(jù)庫中存儲的基本單位是區(qū)塊,區(qū)塊通過哈希指針連接就會構成一顆樹,如下圖所示,圖中綠色的最長鏈就是網(wǎng)絡的主鏈。
blockchain-and-blocks
圖 3 - 區(qū)塊鏈和主鏈
如何讓網(wǎng)絡中的所有節(jié)點對下一個區(qū)塊中的內(nèi)容達成共識是比特幣需要解決的關鍵問題,只有讓節(jié)點對數(shù)據(jù)達成一致才會保證過去的交易不會被篡改,但是作為在公網(wǎng)運行的分布式數(shù)據(jù)庫,它面對的場景非常復雜,需要解決拜占庭將軍問題下的分布式一致性問題。
拜占庭將軍問題是 Leslie Lamport 在 The Byzantine Generals Problem 論文中提出的分布式領域的容錯問題,它是分布式領域中最復雜、最嚴格的容錯模型[^8]。在該模型下,系統(tǒng)不會對集群中的節(jié)點做任何的限制,它們可以向其他節(jié)點發(fā)送隨機數(shù)據(jù)、錯誤數(shù)據(jù),也可以選擇不響應其他節(jié)點的請求,這些無法預測的行為使得容錯這一問題變得更加復雜。
拜占庭將軍問題描述了一個如下的場景,有一組將軍分別指揮一部分軍隊,每一個將軍都不知道其它將軍是否是可靠的,也不知道其他將軍傳遞的信息是否可靠,但是它們需要通過投票選擇是否要進攻或者撤退:
byzantine-generals-problem
圖 4 - 拜占庭將軍問題
區(qū)塊鏈技術使用 共識算法 和激勵讓多個節(jié)點在拜占庭將軍場景下實現(xiàn)分布式一致性。比特幣使用如下的規(guī)則讓多個節(jié)點實現(xiàn)分布式一致性:
- 引入工作量證明 — 讓節(jié)點在提交新的區(qū)塊之前計算滿足特定條件的哈希,取代傳統(tǒng)分布式一致性算法中,一人一票(或者一節(jié)點一票)的設定;
- 引入最長鏈是主鏈的設定 — 只有主鏈上的交易才被認為是合法交易;
- 引入激勵 — 提交區(qū)塊的節(jié)點可以獲得比特幣獎勵;
通過以上的規(guī)則,各個節(jié)點會在最長的鏈上計算哈希,努力提交合法的區(qū)塊。然而一旦節(jié)點中有人掌握了 51% 以上的計算能力,它能通過強大的算力改變區(qū)塊鏈的歷史。因為區(qū)塊具有連續(xù)性,所以前一個區(qū)塊的改變會使后一個區(qū)塊計算的哈希失效,如圖 5 所示,如果攻擊者需要改變主鏈中的倒數(shù)第三個黃色區(qū)塊,它需要連續(xù)構建四個區(qū)塊才能完成對歷史的篡改,其他的節(jié)點才會在這條更長的鏈上繼續(xù)計算:
51-percent-attack
圖 5 - 51% 攻擊
使用如下所示的代碼可以計算在無限長的時間中,攻擊者持有 51% 算力時,改寫歷史 0 ~ 9 個區(qū)塊的概率[^10]:
- #include <math.h>
- #include <stdio.h>
- double attackerSuccessProbability(double q, int z) {
- double p = 1.0 - q;
- double lambda = z * (q / p);
- double sum = 1.0;
- int i, k;
- for (k = 0; k <= z; k++) {
- double poisson = exp(-lambda);
- for (i = 1; i <= k; i++)
- poisson *= lambda / i;
- sum -= poisson * (1 - pow(q / p, z - k));
- }
- return sum;
- }
- int main() {
- for (int i = 0; i < 10; i++) {
- printf("z=%d, p=%f\n", i, attackerSuccessProbability(0.51, i));
- }
- return 0;
- }
通過上述的計算我們會發(fā)現(xiàn),在無限長的時間中,占有全網(wǎng)算力的節(jié)點能夠發(fā)起 51% 攻擊修改歷史的概率是 100%;但是在有限長的時間中,因為比特幣中的算力是相對動態(tài)的,比特幣網(wǎng)絡的節(jié)點也在避免出現(xiàn)單節(jié)點占有 51% 以上算力的情況,所以想要篡改比特幣的歷史還是比較困難的,不過在一些小眾的、算力沒有保證的一些區(qū)塊鏈網(wǎng)絡中,51% 攻擊還是極其常見的[^9]。
防范 51% 攻擊方法也很簡單,在多數(shù)的區(qū)塊鏈網(wǎng)絡中,剛剛加入?yún)^(qū)塊鏈網(wǎng)絡中的交易都是未確認的,只要這些區(qū)塊后面追加了數(shù)量足夠的區(qū)塊,區(qū)塊中的交易才會被確認。比特幣中的交易確認數(shù)就是 6 個,而比特幣平均 10 分鐘生成一個塊,所以一次交易的確認時間大概為 60 分鐘,這也是為了保證安全性不得不做出的犧牲。不過,這種增加確認數(shù)的做法也不能保證 100% 的安全,我們也只能在不影響用戶體驗的情況下,盡可能增加攻擊者的成本。
總結
研究比特幣這樣的區(qū)塊鏈技術還是非常有趣的,作為一個分布式的數(shù)據(jù)庫,它也會遇到分布式系統(tǒng)經(jīng)常會遇到的問題,例如節(jié)點不可靠等問題;同時作為一個金融系統(tǒng)和賬本,它也會面對更加復雜的交易確認和驗證場景。比特幣網(wǎng)絡的設計非常有趣,它是技術和金融兩個交叉領域結合后的產(chǎn)物,非常值得我們花時間研究背后的原理。
比特幣并不能 100% 防止交易和數(shù)據(jù)的篡改,文中提到的兩種技術都只能從一定概率上保證安全,而降低攻擊者成功的可能性也是安全領域需要面對的永恒問題。我們可以換一個更嚴謹?shù)姆绞疥U述今天的問題 — 比特幣使用了哪些技術來增加攻擊者的成本、降低交易被篡改的概率:
- 比特幣使用了非對稱加密算法,保證攻擊者在有限時間內(nèi)無法偽造賬戶所有者的簽名;
- 比特幣使用了工作量證明的共識算法并引入了記賬的激勵,保證網(wǎng)絡中的歷史交易不會被攻擊者快速替換;
通過上述的兩種方式,比特幣才能保證歷史的交易不會被篡改和所有賬戶中資金的安全。到最后,我們還是來看一些比較開放的相關問題,有興趣的讀者可以仔細思考一下下面的問題:
- 你對比特幣的未來是怎么看的?
- 如果要對比特幣發(fā)起一次 51% 攻擊篡改交易要花費多少成本?