1. 程式人生 > >比特幣:一個點對點的電子現金系統

比特幣:一個點對點的電子現金系統

本文由我(samuel)基於2009年Satoshi Nakamoto(中本聰)的論文進行翻譯。之前看過別人寫的中文翻譯,總感覺有點晦澀。現在翻譯如下,如有問題,敬請諒解與批評指正!謝謝各位!

0 摘要(Abstract)

一個純粹p2p的電子現金交易系統能給使得線上支付能夠直接由一方發起並支付給另外一方,不需要通過任何的中間的金融機構。雖然數字簽名(Digital signatures)提供了部分的解決方案,但是,如果需要第三方支援才能防止雙重支付(double-spending)的話,那麼這種電子現金也就失去了其價值基礎。本文提出了使用p2p網路來解決雙重支付(double-spending)的解決方案,p2p網路對全部交易加上時間戳

(timestamps),並將其hash到hash-based的工作量證明(proof-of-work)的鏈條中,生成對應的交易記錄(record)。值得注意的是,除非重新完成全部的工作量證明,否則形成的交易記錄將不可更改。

最長的鏈條(或者說最近的區塊)不僅僅可以作為從開始到現在所有事件的見證者,而且還被看做是來自CPU計算資源最強大的pool(CPU資源池)中。這個系統基本上是穩定的,唯一可能造成這個系統崩潰的原因:就是有一個人/組織擁有超過整個系統51%的計算能力,那麼他就能隨意更改每筆交易記錄,這就是所謂的“51%攻擊”,但這幾乎是無法實現的。
另外,p2p網路本身需要內容不多,要求資訊儘可能在全網傳播,節點

(nodes)可以隨時離開和重新加入網路,只要其回到網路中的時候,將離開網路這段時間的區塊接收並同步即可。

雙重支付:在數字貨幣中,比特幣會對前一次的交易和下一位擁有者的公鑰簽署一個隨機雜湊(hashed)數字簽名,將這個簽名附加在比特幣的末尾傳送給下一位所有者。而由於沒有第三方機構去做監控,所以需要一個機制去確保比特幣之前的所有者沒有對更早發生的交易實施簽名

1 介紹(Introduction)

網際網路上,幾乎所有的交易都需要藉助金融機構作為可信賴的第三方來處理。雖然這類系統在絕大多數情況下都運作良好,但是這類系統具有先天不足——受制於“基於信用的模式”(trust based model)。在這種情況下,想要實現不可逆的交易是不現實的,因為金融機構總是不可避免涉及到糾紛調解處理。此外,由於金融中介等第三方的存在,交易的成本也增加了,並且限制了實際可行的最小交易規模和日常的小額支付交易。另外,由於很多商品和服務本身是無法退貨的,如果缺乏不可逆的支付手段,網際網路的貿易就大大受限。因為交易中有退款的可能,就需要交易雙方的互相信任就非常重要了。

因此商家為了提防自己的客戶的潛在索賠可能性,經常會向客戶提供完全不必要的資訊而非關鍵資訊。而實際的商業行為中,帶有欺詐目的的客戶是不可避免的。在使用現金(physical currency)的情況下,這些銷售費用和支付問題上的不確定性卻是可以避免的,因為此時沒有第三方信用中介的存在。但是目前沒有一種用於保證交易在沒有可信機構保障下順利進行的機制( but no mechanism exists to make payments over a communications channel without a trusted party.)。

因此,我們需要一個電子支付系統(基於密碼驗證/密碼學原理而非信用),使得任何達成一致的雙方,能夠直接進行支付,從而不需要第三方中介的參與。杜絕回滾(reverse)支付交易的可能,這就可以保護特定的賣家免於欺詐;而常規託管機制(routine escrow mechanisms)也有效的保證了買家的權益。在本論文中,我們將提出一種通過點對點分散式的時間戳伺服器來生成依照時間前後排列並加以記錄的電子交易證明,從而解決雙重支付問題。只要誠實節點(honest nodes)所控制的算力的總和大於有合作關係的(cooperating)攻擊者的計算能力的總和,那麼該系統就是安全的。

2 交易(Transactions)

我們將電子coin定義為一個數字簽名鏈(digital signatures)。每個使用者的交易都是將前一次交易和交易物件的公鑰進行hash得到的數字簽名。並將此簽名加到coin的末尾。而收款人(payee)通過對簽名進行檢驗,就能夠驗證該鏈條的所有者。

這裡寫圖片描述

該過程的問題在於:收款人難以檢驗的是:之前的某位所有者有沒有對這枚電子貨幣進行了雙重支付。通常的解決方案,就是引入信得過的第三方權威,或者類似於造幣廠(mint)的機構,來對每一筆交易進行檢驗,以防止雙重支付。在每一筆交易結束後,這枚電子貨幣就要被造幣廠回收,而造幣廠將發行一枚新的電子貨幣;而只有造幣廠直接發行的電子貨幣,才算作有效,這樣就能夠防止雙重支付。可是該解決方案的問題在於,整個貨幣系統的命運完全依賴於運作造幣廠的公司,因為每一筆交易都要經過該造幣廠的確認,而該造幣廠就好比是一家銀行。

我們需要讓收款方(payee)知道之前的擁有者沒有在此次交易前的交易簽署簽名(也就是對已經花出去的錢再次使用···),唯一的方法是需要知道在本次交易之前所有的交易記錄。為了排除第三方機構,交易務必要publicly announced
我們需要整個系統內的所有參與者,都認同唯一的歷史交易序列收款方(payee)需要確保在每次交易期間,大多數的節點都認同該交易是首次出現。

3 時間戳伺服器(Timestamp Server)

在解決方案的最開始,我們提出了“時間戳伺服器”(Timestamp Server)。時間戳伺服器通過對以區塊(block)形式存在的一組交易記錄實施隨機雜湊而加上時間戳,並將該隨機雜湊在系統內進行廣播,就像在新聞或世界性新聞組網路(Usenet)的發帖一樣。
顯然,該時間戳能夠證實特定資料在某特定時間確實存在,因為只有在該時刻存在了才有能獲取相應的隨機雜湊值。如下圖所示,每個時間戳包含在其隨機雜湊中的前一個時間戳,形成了一個鏈條(Chain)。隨後的時間戳會對之前的時間戳進行增強(reinforcing)。
這裡寫圖片描述

4 工作量證明(Proof-of-Work)

為了實現基於p2p的分散式時間戳伺服器,我們需要使用Proof-of-Work系統(跟Adam Back’s 的Hashcash很像)。
在進行隨機雜湊運算時,工作量證明機制引入了對特定值的掃描工作,比方說SHA-256下,隨機雜湊值開頭為一個或多個0bit。那麼隨著0的數目的上升, 找到這個解所需要的工作量將呈指數增長(exponential),而對結果進行檢驗則僅需要一次隨機雜湊運算。

對於我們的時間戳網路,我們通過對每個Block加入Nonce(隨機數)來實現proof-of-work的機制。直到使得這個Block的雜湊值出現了需要的0bits的情況,才說明這個Block的Nonce被找到。我們通過反覆嘗試來找到這個隨機數(Nonce),直到找到為止,這樣我們就構建了工作量證明機制。一旦CPU計算資源開銷能夠滿足該工作量證明機制,那麼除非重新完成相當的工作量,該區塊的資訊就不可更改。由於之後的區塊是連結在該區塊之後的,所以想要更改該區塊中的資訊,就需要重新完成(redoing)該區塊之後所有區塊資訊。
這裡寫圖片描述

工作量證明機制還解決了在集體投票表決(majority decision making)時,誰是大多數(代表)的問題——如果是一個ip一票,那那些擁有很多ip地址的人可能會成為這個系統的權勢人物(The Mighty Man)。因此,我們採用的是基於CPU的方式來做工作量證明機制(”one-CPU-one-vote“)。系統中最長的連結串列示“大多數”的決定,因為最長的鏈包含了最大的工作量。如果大多數的CPU為誠實節點控制,那麼誠實鏈條將以最快的速度延長,並超越其他的競爭鏈條。如果想要對業已出現的區塊進行修改,攻擊者必須重新完成該區塊的工作量外加該區塊之後所有區塊的工作量,並最終趕上和超越誠實節點的工作量。我們將在後面證明,設想一個較慢的攻擊者試圖趕上隨後的區塊,那麼其成功概率將呈指數遞減。

另一個問題是,硬體的運算速度在高速增長,而節點參與網路的程度則會有所起伏。為了解決這個問題,工作量證明的難度機制(the proof-of-work difficulty)將採用移動平均目標的方法來確定,即令難度指向每小時生成區塊的速度為某一個預定的平均數。如果區塊生成的速度過快,那麼難度就會提高。

5 網路(Network)

網路執行的步驟如下:

  • (1) 新的交易向全網進行廣播;
  • (2) 每一個節點都將收到的交易資訊納入一個區塊中;
  • (3) 每個節點都嘗試在自己的區塊中找到一個具有足夠難度的工作量證明;
  • (4) 當一個節點找到了一個工作量證明,它就向全網進行廣播;
  • (5) 當且僅當包含在該區塊中的所有交易都是有效的且之前未存在過的,其他節點才認同該區塊的有效性;
  • (6) 其他節點表示他們接受該區塊是通過在跟隨該區塊的末尾,製造新的區塊以延長該鏈條,而將被接受區塊的隨機雜湊值視為previous的隨機雜湊值。

節點總是認為最長的鏈是唯一正確的,並且保持區塊鏈的延伸。如果有兩個節點同時廣播不同版本的新區塊,那麼其他節點在接收到該區塊的時間上將存在先後差別。當此情形,他們將在率先收到的區塊基礎上進行工作,但也會保留另外一個鏈條,以防後者變成最長的鏈條。僵局(tie)的打破要等到下一個工作量證明被發現,而其中的一條鏈條被證實為是較長的一條,那麼在另一條分支鏈條上工作的節點將轉換陣營,開始在較長的鏈條上工作。

所謂“新的交易要廣播”,實際上不需要抵達全部的節點。只要交易資訊能夠抵達足夠多的節點,那麼他們將很快被整合進一個區塊中。而區塊的廣播對被丟棄的資訊是具有容錯能力的。如果一個節點沒有收到某特定區塊,那麼該節點將會在後續接收到區塊的情況下,發現自己缺失了後續區塊之前的某個區塊。

6 激勵(Incentive)

本質上:每個區塊的第一筆交易是為區塊建立者送一個新的bitcoin。可以類比於挖礦,不過消耗的資源變成了CPU時間和電力。這樣就會促使更多的節點接入此網路。並提供了一種分發電子貨幣到流通的原始方式,因為這個系統是去中心化的(decentralized)。

另外一個激勵的來源則是交易費(transaction fees)。如果某筆交易的輸出值小於輸入值,那麼差額就是交易費,該交易費將被增加到該區塊的激勵中。一旦預定數量的電子貨幣(比特幣是2100萬枚)已經進入流通,那麼激勵機制就可以逐漸轉換為完全依靠交易費,那麼本貨幣系統就能夠免於通貨膨脹。

激勵系統也有助於節點保持誠實。試想如果有一個貪婪的攻擊者能夠調集比所有誠實節點加起來還要多的CPU計算力,那麼他就面臨一個選擇:要麼將其用於誠實工作產生新的電子貨幣,或者將其用於進行二次支付攻擊。那麼他就會發現,按照規則行事、誠實工作是更有利可圖的,而進行二次支付攻擊的話,那麼他自身的貨幣價值也會受損

7 回收磁碟空間(Reclaiming Disk Space)

一旦特定的某枚電子貨幣交易已經被納入了足夠多的區塊之中,那麼就可以丟棄掉此幣(specified coin)交易之前的資料,以回收硬碟空間。為了同時確保不損害區塊的隨機雜湊值,交易資訊被隨機雜湊時,被構建成一種Merkle樹(Merkle tree)的形態,使得只有(root)被納入了區塊的隨機雜湊值。通過將該樹(tree)進行分支拔除(stubbing)的方法,老區塊就能被壓縮。而內部的隨機雜湊值是不需要儲存的。

這裡寫圖片描述

一個不含交易資訊的Block的(Header)大小僅有80位元組。如果我們設定區塊生成的速率為每10分鐘一個,那麼每一年產生的資料為80624365=42MB。以2008年標配電腦2GB記憶體為例,Moore定律表明記憶體增長速度約為1.2GB一年,因此Block Header的儲存應該不會遇到出現瓶頸的情況。

8 簡化支付確認(Simplified Payment Verification)

在本系統中,交易的確認不需要經過所有的網路節點。使用者只需要保留一份最長工作量證明的Block Header的複製——通過請求網路直到確認它獲得的是最長的鏈。並且可以通過merkle的分支通向它被加上時間戳並納入區塊的那次交易。使用者無法自行檢驗該交易的有效性,但通過追溯到交易鏈條的某個位置,使用者可以看到某個節點曾經接受過它,並且於其後追加的區塊也進一步證明全網曾經接受了它。

這裡寫圖片描述

這樣,只要誠實的節點控制了網路,檢驗機制就是可靠的。但是,當全網被一個計算力佔優的攻擊者攻擊時,將變得較為脆弱。因為網路節點能夠自行確認交易的有效性,只要攻擊者能夠持續地保持計算力優勢,簡化的機制會被攻擊者偽造的(fabricated)交易欺騙。

一個可行的策略就是,只要他們發現了一個無效區塊(invalid block),就立刻發出警報,收到警報的使用者將立刻開始下載被警告有問題的區塊或交易的完整資訊,以便對資訊的不一致進行判定。對於每日大量交易產生的商業機構,可能會希望執行他們自己的完整節點,以保持較大的獨立完全性和檢驗的快速性。

9 價值的組合、切分(Combining and Splitting Value)

儘管,我們可以對電子貨幣的交易進行單獨的處理。但實際上,在轉讓過程中為每一分錢進行單獨的交易是很不方便的(比如交易1.2個BTC,我們不能按0.00001BTC為粒度進行交易,這樣太耗費Hash雜湊資源)。為了允許值得合併和拆分,交易可以包含多個輸入和輸出。

一般而言是某次價值較大的前次交易構成的單一輸入,或者由某幾個價值較小的前次交易共同構成的並行輸入,但是輸出最多隻有兩個:一個用於支付,另一個用於找零(如有,則返回給輸入者(sender))。

這裡,需要注意的是扇出性(fan-out),即當一筆交易依賴於之前的多筆交易時,而這些交易又各自依賴於多筆交易。但此處這並不構成一個問題,這是因為此工作機制並不需要對之前發生的所有交易歷史進行重新檢驗。

這裡寫圖片描述

10 隱私(Privacy)

傳統的銀行模型通過限制當事人向第三方可信機構的獲取資訊,從而達到一定程度的隱私保護(achieves a level of privacy)。但是如果將交易資訊向公開傳播,就意味著這種保護隱私的方法失去效力。但是,我們仍然可以通過保護公鑰(public keys)匿名來維護隱私:人們可以看到A向B支付了一定的金額,但是沒有資訊將這筆交易與任何人關聯起來。這跟股票交易所釋出的資訊類似,即:個人的交易時間和交易規模是公開的,但交易當事人是隱藏起來的

這裡寫圖片描述

每筆交易都應有一個新的key pair,從而為避免交易者和現實世界的人對應起來增加額外的保護。在多輸入交易中,某些連結仍然不可避免(Some linking is still unavoidable),這必然表明它們的輸入是由同一所有者擁有的。這裡的風險在於,如果此人的某一個公鑰被確認屬於他,那麼就可以追溯出他的其它很多交易。

11 計算(Calculations)

假設一個攻擊者試圖比誠實節點產生chain更快地製造替代性區塊鏈。即便攻擊者達到了這一目的,但是整個系統也並非完全受制於攻擊者的掌控之中——比方說憑空創造價值(creating value out of thin air),掠奪本不屬於攻擊者的貨幣。這是因為節點不會接受無效的交易,而誠實的節點永遠不會接受一個包含了無效資訊的區塊。所以說,一個攻擊者最多可以嘗試更改他自己的交易資訊,並試圖拿回他剛剛付給別人的錢。

誠實鏈條和攻擊者鏈條之間的長度競爭,可以用二項隨機漫步(Binomial Random Walk)來描述。成功事件定義為誠實鏈條延長了一個區塊,使其領先性+1,而失敗事件則是攻擊者的鏈條被延長了一個區塊,使得差距-1。

攻擊者成功填補某一既定差距的可能性,可以近似地看做賭徒破產問題(Gambler’s Ruin problem)。假定一個賭徒擁有無限的透支信用,然後開始進行潛在次數為無窮的賭博,試圖填補上自己的虧空(reach breakeven)。那麼我們可以計算他填補上虧空的概率,也就是該攻擊者趕上誠實鏈條,如下所示:

這裡寫圖片描述
這裡,p是誠實節點找到出下一個區塊的概率;q為攻擊節點找到出下一個區塊的概率;qz為攻擊節點落後誠實節點z個區塊時候能追上的概率。假定p>q,那麼攻擊成功的概率就因為區塊數的增長而呈現指數化下降。由於概率是攻擊者的敵人,如果他不能幸運且快速地獲得成功,那麼他獲得成功的機會隨著時間的流逝就變得愈發渺茫。那麼我們考慮一個收款人需要等待多長時間,才能足夠確信付款人已經難以更改交易了。我們假設付款人是一個支付攻擊者,希望讓收款人在一段時間內相信他已經付過款了,然後立即將支付的款項重新支付給自己。雖然收款人屆時會發現這一點,但為時已晚。

收款人生成了新的一對金鑰組合,然後只預留一個較短的時間將公鑰傳送給付款人。這將可以防止以下情況:付款人預先準備好一個區塊鏈然後持續地對此區塊進行運算,直到運氣讓他的區塊鏈超越了誠實鏈條,方才立即執行支付。當此情形,只要交易一旦發出,攻擊者就開始祕密地準備一條包含了該交易替代版本的平行鏈條。
然後收款人將等待交易出現在首個區塊中,然後在等到z個區塊連結其後。此時,他仍然不能確切知道攻擊者已經進展了多少個區塊,但是假設誠實區塊將耗費平均預期時間以產生一個區塊,那麼攻擊者的潛在進展就是一個泊松分佈,分佈的期望值為:

λ=zqp

現在,為了計算攻擊者追趕上誠實節點的概率,我們將攻擊者取得進展區塊數量的泊松分佈的概率密度乘以在該數量下攻擊者依然能夠追趕上的概率。

i=0λkeλk!{(qp)zkk<z1k>z}

將上面的方程進行重新排列,用以避免無限級數求和:

1i=0zλkeλk!(1(qp)zk)

C程式碼:

#include <math.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;
}

對其進行運算,我們可以得到如下的概率結果,發現概率對z值呈指數下降。

當q=0.1時
z=0 P=1.0000000
z=1 P=0.2045873
z=2 P=0.0509779
z=3 P=0.0131722
z=4 P=0.0034552
z=5 P=0.0009137
z=6 P=0.0002428
z=7 P=0.0000647
z=8 P=0.0000173
z=9 P=0.0000046
z=10 P=0.0000012

當q=0.3時
z=0 P=1.0000000
z=5 P=0.1773523
z=10 P=0.0416605
z=15 P=0.0101008
z=20 P=0.0024804
z=25 P=0.0006132
z=30 P=0.0001522
z=35 P=0.0000379
z=40 P=0.0000095
z=45 P=0.0000024
z=50 P=0.0000006

求解令P<0.1%的z值:

為使P<0.001,則
q=0.10 z=5
q=0.15 z=8
q=0.20 z=11
q=0.25 z=15
q=0.30 z=24
q=0.35 z=41
q=0.40 z=89
q=0.45 z=340

12 結論(Conclusion)

本文提出了一種不需要信用中介的電子支付系統。首先從數字簽名的一般框架開始討論,雖然這種系統為電子貨幣的所有權提供了強有力的控制,但是不足以防止雙重支付。

為了解決這個問題,我們提出了一種採用工作量證明機制的點對點網路(p2p)來記錄交易的公開資訊,只要誠實的節點能夠控制絕大多數的CPU計算能力,就能使得攻擊者事實上難以改變交易記錄。該網路的強健之處在於它結構的簡潔。節點之間的工作大部分是相互獨立的。在p2p網路中,每個節點不需要證實自己的身份,由於交易資訊的流動路徑並無任何要求,所以只需要盡其最大努力傳播即可。節點可以隨時離開網路,而想重新加入網路也非常容易,因為只需要補充接收離開期間的工作量證明鏈條即可。節點通過自己的CPU計算力進行投票,表決他們對有效區塊的確認,他們不斷延長有效的區塊鏈來表達自己的確認。任何需要的規則和激勵都可以通過這種共識機制(consensus mechanism)來實施。

參考文獻(References)

[1] W. Dai, “b-money,” http://www.weidai.com/bmoney.txt, 1998
[2] H. Massias, X.S. Avila, and J.-J. Quisquater, “Design of a secure timestamping service with minimal
trust requirements,” In 20th Symposium on Information Theory in the Benelux, May 1999.
[3] S. Haber, W.S. Stornetta, “How to time-stamp a digital document,” In Journal of Cryptology, vol 3, no 2, pages 99-111, 1991.
[4] D. Bayer, S. Haber, W.S. Stornetta, “Improving the efficiency and reliability of digital time-stamping,” In Sequences II: Methods in Communication, Security and Computer Science, pages 329-334, 1993.
[5] S. Haber, W.S. Stornetta, “Secure names for bit-strings,” In Proceedings of the 4th ACM Conference on Computer and Communications Security, pages 28-35, April 1997.
[6] A. Back, “Hashcash - a denial of service counter-measure,”http://www.hashcash.org/papers/hashcash.pdf, 2002.
[7] R.C. Merkle, “Protocols for public key cryptosystems,” In Proc. 1980 Symposium on Security and Privacy, IEEE Computer Society, pages 122-133, April 1980.
[8] W. Feller, “An introduction to probability theory and its applications,” 1957.