比特幣的架構、演算與經濟,為什麼 AMD 比 NVIDIA 還好挖?安全有什麼漏洞

作者 | 發布日期 2014 年 04 月 15 日 0:00 | 分類 Fintech , 科技教育 follow us in feedly

話說大約在 2~3 年前,水電工的朋友圈中開始有人提到比特幣(Bitcoin,簡稱 BTC)這種新玩意。近年來在網際網路上,許多公司不斷嘗試提供所謂的金流以及虛擬貨幣的服務。好比水電工本人就曾在某些網遊公司打工,虛擬貨幣的發行、遊戲中寶物的發行和維護,其實都是類似的東西。當然礙於法律規定,遊戲公司是不可能花錢回收代幣及寶物的,但是這些虛寶在實體世界中仍會有同好不斷地轉手收售。



起於密碼學大師

在美國更有某些快速線上付款服務,可讓您先購買點數後再去特約商店消費,凡舉這類型的服務,都算金流的一部分,因此從點數的發行到維護等,都是需要投資成本,同時也需要大量的網路安全及系統架構相關知識。否則一旦駭客入侵,即可能讓虛寶的公信力驟失,甚至讓使用者蒙受大量的損失。

比特幣則比上述的各種金流服務更趨近無政府主義者的理想,能不能有種貨幣,在沒有中央發行單位的管理下,由使用者自行運作且擁有更高的公信力,進而可能取代現有的各種貨幣?由化名中本聰(Satoshi Nakamoto)的某位密碼學大師的某篇論文中,提到某種方法來達成這個目標,在本文中我們要來看這種方法的好處及問題。

運作首重安全性

比特幣使用許多方式來試圖達成安全性及不可否認性,首先,比特幣並沒有實體的貨幣,甚至就算是深入比特幣資料庫中去看,也完全沒有密碼或編碼本文可以代表某個比特幣,因而沒有人可以拷貝、偽造出比特幣。所謂的比特幣,是利用雙金鑰密碼安全系統進行數位簽名的一連串交易紀錄。嚴格說來,就水電工自己認為,比特幣與其說是種電子貨幣,還不如說是大家更為熟悉的 P2P(peer-to-peer,點對點)服務。只要使用者將交易紀錄利用私密金鑰加簽,並發佈到網路上,原則上就算是交易成立了。

虛擬交易的驗證方式

由圖 A 我們可以看到中本聰對交易的設計是這樣:由第一位所有者,發布一個交易訊息到網路上,這個訊息的意義通常是「使用者 1 要轉移 n 個比特幣給使用者 2」這類的訊息,這個交易訊息並不是單純的交易本文,而是包括了利用使用者 1 的私密金鑰加密過的電子簽章,若不知道使用者 1 私密金鑰是無法偽造這個訊息的。且任何一個知道使用者 1 公開金鑰的人,都能可以用公開金鑰來檢驗這個訊息的真假。

雙金鑰密碼系統

世上有許多形式的密碼系統,而雙金鑰型是應用層面最廣的類型。這種密碼系統的最大特色,就是使用者擁有兩把密碼金鑰。每把密碼金鑰都是極長的數字,好比 1024bit 的超長整數;由於金鑰的位元數極長,要靠瞎猜來猜到使用者的密碼機率趨近於零。兩把金鑰中,其中一把是公開金鑰(Public Key),可以發佈到網路上,另一把則是絕對不能給第三者知道的私密金鑰(Private Key)。

這個系統的好玩之處在於,任何人的公開金鑰都能讓所有人知道,而私密金鑰則是用來進行電子簽章或解密文件,也就是這兩把鑰匙是成對的。假設 A 要發布電子簽章,就利用 A 的私密金鑰來加簽某段本文,任何人只要擁有 A 的公開金鑰,都可以利用這個公開金鑰確定這個本文和簽章的確是由 A 本人產生。

若是 A 要傳送加密文給 B,就要用 B 的公開金鑰套進加密演算法中把本文加密,加密後的密文,只有用 B 的私密金鑰才能解開。由於這種方便特性,使 PKI 成為目前商業交易最常使用的密碼系統,大名鼎鼎的 RSA 和 Elliptic Curve(ECC)演算法就是用來實做這個雙金鑰系統。

光是如此並沒有辦法防止假造的交易,好比若是使用者 1 是個邪惡的駭客,他帳戶裡明明只有 10 個比特幣,卻在網路上公開發表說他要送 1,000 個比特幣給使用者 2;或他同時送了使用者 2、3、4 各 10 個比特幣,這時要怎麼辦呢?

中本聰在設計這個系統時,便讓它成為 P2P 系統,每個參與這個系統的人,都可以且必須得到過去到現在的所有交易紀錄,每個人經過掃瞄歷史交易資料後都可以確認使用者 1 到底有幾個比特幣可以發送,若發現是來亂的,就會將這個交易資料刪除。由於沒有實體的中央控制伺服器,因此在這麼多使用者間維持交易資料的一致性和真實性就成了重要課題。在比特幣網路中,使用者的交易資料會照發生的時間集結成資料塊(Block),並發送到每位參與者的電腦,由於不見得每個人都隨時上線,因此只要有 6 個節點承認收到這個資料,就算發布成功了。

如何防止偽造歷史資料

如前段所述,比特幣最重要的靈魂就是歷史交易資料,因此必須想出方法讓它無法輕易修改。同時比對每位使用者的資料庫是個方法,但是這方法太鳥了。中本聰使用的方式是利用 Hashcash 演算法,對每個資料塊做雜湊運算(Hash Function)並把結果記錄起來,代入下個區塊中。

這作法叫 proof-of-work,由於 Hashcash 很花時間,除非出現某台比全網路用戶電腦總計算力加起來都還強大的外星人電腦,否則一定無法在全體善良用戶算出真實結果前偽造現在的交易資料塊,如果要竄改歷史資料,那所要花的工夫就更可怕了,得從你想改的時間點的特定區塊開始,一直重做雜湊運算直到現在時間點為止,還得強迫每個人都相信你這台電腦的結果才是對的。所以偽造這件事,在目前比特幣的運作來說很困難。

隨時間增加運算難度

Hashcash 有個好用的特性,那就是難度可以調整。比特幣的歷史資料串在一開始是使用較簡單的設定條件,所以很好找到符合條件的解,越到後期就用越難的條件,因為參與的人增多,計算力就越強大。比特幣的設計上,是希望使用者發布出來的交易訊息在 10 分鐘左右可以被加入歷史資料串,一旦被加入就完全不可否認或反轉,才會有人說比特幣交易需要 10 分鐘左右的確認。

若是在一堆電腦都在做 Hascash 的情況下難度還不改變,那麼可能不用 2 秒就可以加 1 個資料區塊到資料串中,這樣也會造成同步上的巨大問題,同時也會讓駭客可以更簡單竄改歷史紀錄。因此比特幣的系統設計上,會自動增加歷史資料串的 Hash 難度,只要現在的資料塊做完 Hashcash 得到結果,就會自動發布到網路上,這時交易就完全無法否認了。

比特幣的產生原理

各位讀者大概要問,講了這麼多,怎麼還沒講比特幣是怎麼生出來的啊?當然這樣設計精良的系統,可以用很多種方式產生貨幣的初始交易資料,好比說中本聰能在他本人初始帳號中放進數億個比特幣,全天下的人都要向他本人領取。不過這位隱形水電工先生,顯然是個打死都不想接信件和電話的人,所以他用了一個便捷的方式,就是在前段我們提過的內容,將所有交易資料打包成資料塊,而資料塊做完 Hashcash 後就會加入歷史資料串。

我們一看所有的歷史資料塊,就會發現,每個找到 Hashcash 解的節點,都會得到一定數量的比特幣,每個資料塊的第一筆交易資訊就是「有 n 個比特幣產生了,他的所有者是 X 先生」。我們來看看全世界第一個比特幣,這筆資料存在 Block 0 中:

Block 0

Short link: http://blockexplorer.com/b/0

Hash: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f

Next block: 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048

Time: 2009-01-03 18:15:05

Difficulty: 1 (“Bits": 1d00ffff)

Transactions: 1

Total BTC: 50

Size: 285 bytes

Merkle root: 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b

Nonce: 2083236893

這個資料塊就是中本聰本人發布的第一筆,我們可以看到當時 Hash 難度只有 1,而解開 Hash 的獎勵就是 50 個比特幣。按照系統的設計,每位使用者會檢查資料塊產生的時間、難度以及應得的數量,所以想要欺騙大家,解開一個 block hash 就產生 1,000 個比特幣也不太可能。

▲ 最初的比特幣是由中本聰發布,共計有 50 個比特幣,當時難度只有 Hash 1 而已。

挖礦一詞的起源

就原本設計者的想法,比特幣的交易有可能需要付費,但目前為止除非是大量區塊改變,否則應該沒有人付過費用,但在通訊協定中的確看到了付費欄。之前已經提過,所有即時的交易資料會收集起來變成資料區塊,交由網路上的使用者做 Hashcash 找到解,再加入歷史資料串中。由於做 Hashcash 要花費電力和網路頻寬等資源,所以此系統在設計上,對開放自己電腦服務的人給予一定的金額獎勵。尤其在早期的運作狀態下,不但難度較低,而且獎勵金額也較高。這個動作叫做挖礦。

比特幣的設計對挖礦者的總計算力有嚴格的管控機制,一旦總計算力增加,不但 Hashcash 難度會增加,而且愈到後期給的獎勵愈少,目前的獎勵只有 25 比特幣,目的是讓未來世界上只有固定數量的比特幣。直到網路上沒有挖礦者,那麼比特幣就會停止運作,因為沒有人打包交易資料到歷史資料串。

由於歷史資料串是大家一起算的,有時有可能出現你算的結果和我算的結果不同,所以系統在設計上使用競爭方式決定資料樹的最後走向。就是讓最先產生下個資料串的人變成歷史主流,而非主流則被淘汰。

用電子錢包來交易

要使用比特幣並不難,甚至您也可以不用知道前述所有的事。在網路上已經有很多人告訴我們,只要下載各式電子錢包就可以使用比特幣了,加入這個網路後,您會得到一個比特幣位址,一個公開金鑰和一個私密金鑰,公開金鑰和位址是放在一起公開的,我們稱之為比特幣位址,它就如同銀行帳號。私密金鑰就是您自己設定的,如常見的銀行提款卡密碼,絕對不能讓其他人知道。

電子錢包最主要的功用,就是向網路節點發布交易訊息,並且向網路確認這個交易訊息已經放入邪惡的歷史本文中(編輯部:水電工你以為你在寫海賊王嗎?)。比特幣的交易中至少要有一方有電子錢包,通常收錢方一定要有,不然你也無法確定錢收到了沒有。至於付錢方基本上不用,連歷史本文也不用下載(編輯部:還來啊?要不要請魯夫收個件?),因為你的存款餘額是由全網路用戶一起幫你計算。

如果你在網路上收了一堆比特幣想做成離線定存,也很簡單,就是把電子錢包列印到紙上,那上面就有你的地址、金鑰等資料,不包括巨大的歷史資料串,然後就可以砍了這個電子錢包。只要你在想花錢時,到另一個電子錢包軟體輸入這串個人資訊,就會取得這個帳號的控制權。至於您的金額等交易紀錄,都已寫在歷史資料串中,存於千千萬萬的挖礦者電腦,除非他們大量離線或損壞,否則不可能偽造或更改。

比特幣也可以找錢

就比特幣的運作原理而言,電子錢包不用備份,只要記得自己的地址和密碼就一定可以取回帳號。但問題出在找錢或分割錢幣這個動作。比特幣的找錢機制基本上是摧毀舊有的錢幣,然後生出新的 2 個錢幣來。好比說我從地址 A 中,原本有一個 10.88BTC 的錢幣,現在要送給地址 B 的用戶 10BTC,那麼系統實際運作的方式是把這個 10.88BTC 摧毀,產生一筆 10BTC 的交易送給用戶 B,但是偏偏找零的動作不見得會送回原地址 A,經常會產生一個新地址 C,系統再把 0.88BTC 送給這地址 C,但這個地址 C 和您原本的地址 A 都可以直接用您的電子錢包軟體管轄。

其實很多電子錢包在安裝時就會建立 100 個地址,就是用來處理這種分割和找零的動作。人腦可以記得一兩個地址就了不起了,100 個自然記不起來,所以電子錢包需要常備份。老實說這個設計實在不好,應該是為了加速掃瞄歷史資料串的一點犧牲。我們來看最近的歷史本文區塊,有時會有很多帳號一起送錢到某個帳號去,又被找零回來,都是在執行銷毀舊幣創造新幣。

有趣的是在第三欄中,地址 183YHaE144bzof6JgwHsUaDKoeWVmteJKR 送了 0.0311818BTC 到 1GytBMQX9hsx1GHH9PLXpKgLvVt3XmGZ9g 去,它是先把原存在帳戶中的 0.00462164BTC 銷毀後,放了 0.0311818BTC 給對方,又在原地址存回 0.00100346BTC,所以事實上找零也是可以放回原地址。且最近多數交易都開始有手續費了,發現了嗎?

挖礦靠 SHA-256 運算

比特幣網路中負責撰寫邪惡歷史本文的就是礦工,礦工要做的事有很多,包括確認每筆交易的正確性,保持歷史資料串的走向正確,以及最麻煩的就是為每個資料塊加上 Hashcash 的解。事實上礦工就是比特幣的運作中心,而挖礦有多種合作模式,包括加入礦池(mining pool)或私人合作挖礦,或是單獨挖礦。

比特幣的挖礦採用 SHA-256 運算法,因此要單獨靠自己挖礦必定要很久才可能挖到礦,甚至永遠不可能挖到。你想想別人的礦池中有一堆大型專用機在運算,每次一有新 block 出來,大部分的運算量都被別人搶去了,要剛好搶到有正確解答的區段來運算,又要比別人快,那難度有多高啊?使用 CPU 和 GPU 挖礦最近也變困難,因為有些專用挖礦機使用 ASIC(Application Specific Integrated Circuit,特定應用積體電路)來做 Hash,效能可達到 600GHash/s,足足是 CPU 的 50,000~100,000 倍,一般小 ASIC 的 2,000 倍。所以近來挖礦熱潮也稍減,畢竟能投資數 10 萬元買挖礦機的人也不多。挖礦程式在您買挖礦機時應該都會隨機附贈,大多也都是由主版本修改,在 Bticoins 也可以下載。

若是您希望有較高機率拿到比特幣,水電工建議您當然要加入礦池,因為礦池中一旦有人挖到,就會按照大家的貢獻程度來分這 25 個比特幣(未來會愈來愈少),同時也放棄靠 CPU 或 GPU 的想法。當然比特幣的原始設計中沒有礦池這東西,也就是分配的動作是靠礦池主人自己做,因此有可能會被礦池主人獨吞。幸好目前為止大多數礦池主人仍然維持菁英主義和無政府主義下的最高道德標準,沒發生什麼糾紛過。不過水電工得說,這種道德標準,在網路發展史上也很常見到就是了。

為什麼 AMD 挖比較快?

目前有在挖礦的人都知道,靠 GPU 挖礦比 CPU 快了很多倍。且大家還發現 AMD 的 Redon 79xx 高階顯卡比 NVIDIA 高階顯卡快了許多,但在其他表現上又常是顛倒的,這點引起許多支持不同品牌的玩家爭論。水電工在此也順便探討一下為何 HD 7970 會比 NVIDIA Tesla M2070 都還快的原因。附帶一提,Tesla M2070 並不是單純顯卡,Tesla 系列都是超級運算專用的硬體。

挖礦使用的演算法當然就是 Hashcash,所謂的 Hash 就是把某個向量空間的向量,也就是一群數字,透過演算法映射到另一個向量空間,它和線性代數中的映射不一樣的地方在於不保證一對一映射,空間大小也不相同。好比有個最簡單的 Hash 法就是個人的身分證字號最後一碼檢查碼,它能保證在一定程度下別人無法憑空瞎編一個字號出來,或輸入不小心的錯誤。用在密碼學上當然複雜許多,好比 MD5 就長達 128bit,而比特幣使用的 Hashcash 更長,達到 256bit。基本上前段提到礦工就是不斷在找個解,那是什麼解呢?Hash 的運作方式基本上就是一串數字資料經過某個演算法,在另一個空間中得到另一個數字,如圖所示:

▲ Hash 雜湊演算法就是把空間一中的數字經由一個演算法映射到空間二中,在大多數情況下空間二都比空間一小,所以未必是一對一映射。

Hashcash 的作法就是在那串資料前加上某個數字,然後把整大段數字丟進 Hash 中,看映射出來的數字前面有幾個 0。如果對方要求您找到某個數字,代入 Hash 後得到的結果只有一個 0,那還算簡單的,如果高達十多個 0,難度就很高了。這個演算法當年設計出來是為了防止亂發廣告信的人,因為每發一封信就得重算一次,所以支援 Hashcash 的 email 伺服器就可以要求來信者每封信都算一次 Hash,這對真的要寄信的人沒什麼差別,頂多等個幾秒,但對發送極大量廣告信的人來說問題就大了,電腦可沒辦法在幾分鐘內算出數千個 Hash 解。

目前常用的雜湊函數幾乎都是單向,也就是我們可以從空間一中的數值套公式找到空間二的對映數,但無法由空間二中的數值找到空間一的對應數值,就算找到了,恐怕也不只一組解。所以無法自己創造前面帶有一堆 0 的數字,然後去反推空間一中的數值為何。也就是如果有人告訴你:空間一中的數值 A 可以產生空間二中的數值 B,而且這個數值 B 滿足前面有 20 個 0。那就代表了這個人在空間一龐大的數字中(可能要試超過數億次),真的一個一個找,才找到這個可以產生數值 B 的 A 值。因此每秒能計算多少次 SHA2 雜湊運算就成了挖礦的唯一指標。

無心插柳造成效能落差

回到 GPU 層面來看,在許多效能測試中能發現 AMD 的 HD 7970 比 GTX TITAN 快了一截,但是在採礦時則差得更多,就演算法分析來看,比特幣使用的雜湊運算主要基於 SHA256,其中會用到大量 32 位元整數位元旋轉計算,就專家看法,目前都認為差異之處就在此。AMD 架構中可以使用一道指令就做完位元旋轉,而 NVIDIA 的架構中則要 3 道指令才能達成同樣的動作。顯然 NVIDIA 做完這 3 道指令所花的總時脈數也比 AMD 多了不少。

水電工認為此實屬不幸的巧合,或說 AMD 在設計 GCN(Graphic Core Next)架構時,很巧合地符合密碼演算的需求,或許這原本就是研發團隊的本意。各位可以注意數據中 NVIDIA 的 GTX TITAN 因為針對位元偏移指令改過了 ALU(Arithmetic Logic Unit,算數邏輯單元)設計,因此效能馬上就和 HD 7970 拉近不少。不過因為 GTX TITAN 的 SMX(Streaming Multiprocessor)只有 14 個,而 HD 7970 的 CU(Compute Unit)有 32 個,因此在平行化的程度上 HD 7970 仍然大勝 GTX TITAN,反應在效能上,我們也可以發現 HD 7970 仍然比 GTX TITAN 快了近一倍。但是這些數字和現在專門為計算 Hash 設計的挖礦機相比,都是滄海中的一粟而已。

比特幣並非安全貨幣

讀者看了這麼多關於比特幣如何安全、如何好用、如何有未來的媒體文章後,想必第一個冒出的想法就是:比特幣真的是安全的未來性貨幣嗎?水電工大膽地告訴各位:「不是」。

第一個理由,比特幣根本不是貨幣。貨幣在金本位主義之後,代表的是持有者的信用,因此貨幣本身必然要有信用,而這個信用本身必須花很多成本去支持,好比世界上有人敢不承認美元,就準備吃老美的子彈……呃,沒這麼嚴重啦,是世界上有人敢偽造美元或對美元展開經濟戰,就準備吃老美的子彈。作戰和捉賊都得花錢,比特幣本身利用的是公共支持的演算法來代表貨幣安全性,那有沒有可能隨時有另一套更新且更好的演算法取代它呢?當然有可能!到那時比特幣又能代表什麼呢?

必然的通貨緊縮現象

就算我們暫時承認比特幣是種貨幣,貨幣本身就只能是信用的代表,一般而言不受控的通縮和通膨對貨幣都是不正常動作。各位看看比特幣和美元的兌換率一路狂飆,搞到錢愈來愈值錢,這正好是種嚴重的通貨緊縮現像。

一般而言,隨著經濟成長,貨幣也發行愈多,因為參與的人和量都變多了。完美的貨幣發行量×貨幣周轉率,要隨時等於物價,也就是勞務加上商品的總量。如果貨幣太少,使用者就會深感不便,同時投機者就會開始收集貨幣本身。當錢愈來愈值錢,這就是通縮,是打垮貨幣經濟的一個大利器。抵抗通縮的妙法就是以物易物,但這樣貨幣存在的必要性不就等於 0 了嗎?

比特幣的發明人非常聰明地認為,只要控制發行總量未來就不會有通膨問題,但是卻造成必然發生的通縮問題。現在大家都依附在現存貨幣之下不覺得有什麼,等到真的把比特幣當貨幣使用,那災難就不遠了。通膨不是人為罪惡,而是經濟成長必然的過程,水電工打個不太精準的比方,您努力工作 20 年,存款從小時候的 10 元變成了 10,000,000 元,這 10,000,000 元都是發行的貨幣,若是世界人口穩定小幅成長,每個人都有存款,貨幣不是必然變多的嗎?電腦專家和經濟專家設計出來的東西必然不同,但可否代替現有的經濟產品?水電工認為隔行如隔山,少下手為妙啊!

礦工人數少就有弱點

其次,比特幣使用的技術是否安全?事實上在水電工眼裡,比特幣使用方式的安全性也有限。尤其當活動的採礦節點變少後,或者是發展前期採礦節點比較少的時候,根本不堪一擊。歷史紀錄的區塊是靠多數採礦者檢查一致性來達成,若是有夠多的節點程式被修改或故意來搗蛋,那麼歷史本文區塊的連結樹就有機會被某組人馬修改成功,只要多出現幾次,整個貨幣的發行和信用就完蛋了。在比特幣發展初期的確就發生過,只是後來被弭平了。

現在的採礦者當然多了,因為目前為止算出一個 block 仍然有 25 個比特幣的所有權,但未來呢?未來的採礦者很可能不會有任何新發行的貨幣可以拿,那麼誰還想當笨蛋去支持這個體系?除了要算一堆 Hash,還得儲存比對所有歷史資料。到時比特幣要如何維持每 10 分鐘處理一筆交易?水電工認為到時必然會收取交易手續費,但比特幣本身發行量就已不足了,採礦者又變少,手續費說不定又會因為計算需求量驚人而變高,根本十足是個自我毀滅設計。

交易 10 分鐘節奏太慢

談到另一種安全,比特幣每筆交易都要等 10 分鐘才能確認,而且一定要有足夠的網路才能廣泛交易,請問各位讀者,上山買個泡麵能用比特幣嗎?交個停車場費用,通行費能用嗎?在現實生活中很多交易要快速進行,誰又有那個美國時間等 10 分鐘呢?這樣對使用者而言是一種很不安全的設計,所以比特幣目前仍然只是自認持有科技者拿來炒作,並且兌換為現有貨幣的一種期貨工具。這樣一來和天幣等遊戲中的虛寶又有何不同呢?

比特幣由開始乏人問津到目前炙手可熱,中間有幾個很大的推手,包括一些毒販(好比 Silk Road)以及洗錢公司,基本上早期的需求都是由這些人創造出來的,無論如何最終目標竟然都只是獲得美元,相信這種情況也不是比特幣推廣基金會樂見的。獨立於政府的貨幣這條路,恐怕還是條要走很久才能看到方向的長路!而這些大量生產的採礦機,水電工實在很怕變成發送垃圾信的利器,讓所有使用 Hashcash 限制垃圾信流量的伺服器,全部承受意料之外的大量暴力攻擊。究竟這齣鬧劇未來會如何發展,讓我們繼續看下去吧……

(本文由 T客邦 授權轉載)