學習區塊鏈技術,一定需要瞭解比特幣的運作,而比特幣又涉及大量的密碼學知識,例如密鑰(私鑰、公鑰)、對稱加密、非對稱加密、散列(Hash)、橢圓曲線加密法等等,亦要瞭解它們彼此之間如何相互配合,而形成有效的交易機制。
密鑰
私鑰
比特幣中的私鑰 Private Key 是使用 SHA-256 算法隨機生成 32 bytes(256bits)的隨機數,而這個隨機數的作用就相當於"密碼"的作用,能夠證明對該比特幣地址的所有資金具有的所有權及控制權。在進行支付的時候,擁有者就必須要使用私鑰為交易"簽名",以證明自己是這個比特幣地址的擁有者,而能夠動用這個比特幣地址賬戶內的比特幣,從而進行交易。
比特幣中私鑰通常由51 個字符或52個字符表示,編碼方式與比特幣地址相似。
使用51個字符的私鑰通常由"5"開頭(主網用"5"開頭,測試網絡用"9"開頭),例如:
5JmXoYTRXPvWufwVEw9KyVFLGSDWPpUAiygKV9S2ouQ8YxRCPCo
而使用52個字符的私鑰通常由"K"或"L"開頭(主網用"K"或"L"開頭,測試網絡用"c"開頭),例如:
KzPkBcF6BHR1pM2oAjCDR4wUAUtxbHcVVjN9R162w1asuhzcCSwY
生成一個比特幣私鑰在本質上與從 1-2^256之間選一個隨機選出一個數字相似,私鑰可以是1~n-1之間的任何數字(n是一個常數,為1.158*1077,略小於2^256),並由⽐特幣所使⽤的橢圓曲線的階所定義。
比特幣中私鑰的使用的 SECP256K1 標準所定義的一種橢圓曲線算法,空間大小為 2^256。
註:SECP256K1 標準由美國國家標準與技術研究院(NIST)設立,定義了一條特殊的橢圓曲線和一系列數學常數。
公鑰
比特幣中的公鑰 Public Key 公鑰是基於私鑰對應生成的,主要用於對整個網絡中的節點,為交易的有效性進行驗證。確保交易是由擁有所對應私鑰的人所發出的。公鑰是從私鑰通過橢圓曲線算法計算而得到的,而這個過程,目前被公認為不可逆轉,因為在橢圓曲線算法中,K(公鑰)=k(私鑰) * G(生成點的常數點),如果反過來要由私鑰k算出公鑰K,則被稱為「離散對數分解」,在目前來說,要窮舉所有有可能的k值是相當困難的。下面的橢圓曲線算法將會進行詳細介紹。
簡單來說,根據橢圓曲線算法,從私鑰可以計算出對應的公鑰,但反過來,由公鑰則不可能計算出對應的私鑰。
對稱加密 Symmetric Encryption
對稱加密簡單來說就是指加密、解密的過程都是使用對一個密鑰,也只有一個,常用的對稱加密算法有AES, DES等等。
例如:發送者對原來的訊息使用密鑰(key)加密,而對方收到的加密訊息,也必須用同一個密鑰才能解密,其他密鑰將無法解密。
非對稱加密就是指加密、解密分別使用兩個不同的密鑰,一個是公開的密鑰,簡稱公鑰,另一個是私有的密鑰,簡稱私鑰。而兩者之間,由公鑰加密的訊息,只有私鑰才能解密,相反,由私鑰加密的訊息,只有公鑰才能解密。相比於對稱加密,非對稱加密採用了兩個不同的密鑰進行加密、解密,發送者取得接收者的公鑰並將訊息加密,而加密的訊息只有接收者的私鑰才能解密,雙方之間亦不毋須擁有對方的私鑰就能完成整個加密、解密的過程,而最常用的非對稱加密算法有RSA。
橢圓曲線算法 Elliptic Curve Cryptography
橢圓曲線算法是密碼學中一種基於離散對數問題的非對稱加密法,在1985年,由Neal Koblitz和Victor Miller分別獨立提出,可以用對橢圓曲線上的點進行加法或乘法運算來表達。
若要理解橢圓曲線算法,需要另起新的篇章再作詳細介紹,本篇主要講述一些基本概念及彼此間產生的關係,故此部份內容容許我暫時跳過,往後將會補寫一篇詳細介紹,有興趣的朋友可以看看以下這篇文章:
比特幣錢包地址
比特幣錢包地址是透過公鑰進行SHA-256散列,再通過RIPEMD-160散列運算得出並利用Base58將之編碼成一個由數字和英文字母組成的字符串,固定長度為160個比特(bits)。為了方便識別,由公鑰生成的比特幣錢包地址以數字"1"或"3"開頭,地址中的英文區分大小寫,但不包括"I"、"l"、"O"、"0"等易誤認的字符,而"1"開頭的地址長度為26~34位,"3"開頭的地址長度為34位。人們為了方便傳播,更可將地址產生二維碼(QR Code)方便其他設備掃瞄讀取。
1DckBL9QbU99vKNJKcv6BMWxNFtg8eo1Tf
這就是平時用來收款的比特幣錢包地址,這個地址就好比銀行賬號,你可以提供給任何想給你轉賬比特幣的人,而且,得到一個比特幣錢包地址不毋須實名登記,沒有包含任何個人信息。當你需要使用這個錢包地址的比特幣時,就必需提供公鑰及交易"簽名"(這個簽名就是使用上述提及的私鑰加密的)。
"1"字開頭的比特幣錢包地址是 P2PKH(Pay-to-Public-Key-Hash)地址,顧名思義,它是由公鑰的 Hash 構成,所有人都可以向這個地址轉入比特幣,但如果要轉出,就必須要有對應的私鑰,轉出的時候要有公鑰和私鑰簽名。
"3"字開頭的比特幣錢包地址是 P2SH(Pay-to-Script-Hash)地址,與P2PKH不同的,當向這個地址轉入比特幣時,除了需要公鑰,同時也需要私鑰簽名作為證明。P2SH地址通常用於多重簽名,但不一定完全是多重簽名,也可能是其他的腳本(Script)。多重簽名主要作用是對於有 N 個密鑰但需要 M 個簽名的情況下,比如需要多個人對一個交易簽名確認,其中 M <= N。
一個人可以生成並擁有很多比特幣錢包地址,並用於不同的交易中,可用的比特幣錢包地址數量高達 2^161個。
要生成比特幣錢包地址,一般可以用設備上的比特幣錢包客戶端或網頁錢包應用生成,在產生比特幣錢包的地址的同時,會產生相對應的私鑰,就好比你買了一個保險箱,肯定會有鑰匙一樣。不,或者這樣說,實際上應該是先會產生私鑰,然後再一步步生成錢包地址(下面會有詳細的生成過程說明)。所以,比特幣中私鑰是公鑰、錢包、地址的根本,故此保管好私鑰,也是必須的,而且,個人建議最好使用可靠的比特幣錢包客戶端離線生成錢包地址,私鑰保存在本地,而非其他網頁的伺服器上。
比特幣錢包
比特幣錢包是私鑰的容器,通常是透過一個簡單有序的文件或數據庫,但錢包並非直接保存比特幣的本身,用戶很少會直接看到比特幣錢包中的密鑰(私鑰和公鑰),它們被存儲在本地錢包中,所以,它其際上是一個私鑰、比特幣錢包地址及區塊鏈數據的管理工具。
簡單來說,比特幣錢包的核心功能就是生成、儲存及使用私鑰去完成交易。
每個用戶都可以有一個包含多個私鑰的錢包,而錢包中多個私鑰也可以產生多個公鑰,用於管理多種不同的加密貨幣,每次交易時,客戶端將會使用這些私鑰來為交易"簽名",並提供公鑰,從而證明擁有及可以使用比特幣作交易輸出。
由於私鑰存在多種的生成方法,所以同時也對應著不同的錢包結構,一般而言,主要分為"非確定性錢包"及"確定性錢包"。
非確定性錢包
非確定性錢包只是隨機生成的一堆私鑰的集合。這種錢包也被稱作零型非確定錢包。最早的比特幣錢包客戶端 - Satoshi client 就是一個非確定性錢包。它會預先隨機生成100個私鑰,並且每個私鑰只使用一次,所以它還有個別名"JBOK"(Just a Bunch Of Keys),每次交易都使用一個不同的私鑰,這個概念是由中本聰提出。非確定錢包在交易次數少的情況這比較容易管理,但交易次數頻繁的情況下,非確性錢包的缺點就顯然易見:難以管理及備份。由於生成很多私鑰,就妥善保存及備份這些私鑰,也就是造成管理複雜度大大增加,一旦錢包出現不能訪問的情況,錢包內的比特幣也將隨之失去控制,所以零型非確定性錢包並非作為一個長期穩定錢包的好選擇,所以目前主流均使用確定性錢包。
確定性錢包
確定性錢包的私鑰是透過一串由隨機數生成的種子(Seed)隨機數進行單向Hash運算生成的,而確定性錢包只需要有這個種子,就可以找回錢包內所有經這個種子生成的私鑰,所以,只需要備份這個種子就相當於備份了整個錢包,亦可以導入導出,故需要妥善保管。
分層確定性錢包(HD錢包)
分層確定性錢包(Hierarchical Deterministic Wallet),又簡稱"HD錢包",當中分層的意思,可以簡單形容為一個組織結構,組織可以為每同部門生成不同的私鑰,而每個部門又可以為部門以下的部門生成不同的私鑰,每個部門可以管理自己的資金及記錄,簡言之,就是分權管理。這個概念最早由 Pieter Wuille 於 2012年02月11日提交的 BIP32 中提出,直至2016年6月15日才正式被合併至比特幣的核心代碼。由於是確定性錢包,所以也會透過種子生成主私鑰,而家再生成大量的子私鑰及地址,而這個種子是一個很長隨機數,如果要記錄或記憶,也相當不容易,所以後來擴展了原有 HD 錢包的 BIP32 出現了 BIP39,將種子將化為一串助記詞匯幫助記錄或記憶。
BIP0039定義助記碼和種子的創建過程如下: 1.創造一個128到256位的隨機順序(熵)。 2.提出SHA256哈希前幾位,就可以創造一個隨機序列的校驗和。 3.把校驗和加在隨機順序的後面。 4.把順序分解成11位的不同集合,並用這些集合去和一個預先已經定義的2048個單詞字典做對應。 5.生成一個12至24個詞的助記碼。
助記詞匯其實就是一些以英文單詞序列代表作為種子所對應的確定性錢包的隨機數,比如 "Mary", "Include", "Car" 等等的一些詞匯,而這些詞匯的次序也是有關係的。透過這些助記詞及它們的次序就可以重建種子,並從種子重建錢包及所有私鑰。
除了 BIP32、BIP38、BIP39,還有 BIP43、BIP44等等。
BIP43:對原 BIP32 進行了擴展,在原來的樹結構中增加了子索引標識 purpose "m/purpose'/*"。
BIP44:對原 BIP43 及 BIP32 的基礎上新增多種幣種,通過 HD錢包可以同時管理主網和測試網的比特幣,而 BIP44更提出了五層的建議路徑:"m/purpose'/cointype'/account'/change/addressindex",BIP44 讓用戶只需要儲存一個種子,就可以管理所有幣種及其錢包。
比特幣錢包管理著私鑰,私鑰就是所有擁有比特幣的根本,保管私鑰就代表要保管好錢包,目前大部份人都會使用比特幣客戶端或一些交易所在線生成私鑰,存儲私鑰的介質通常在直接儲存在設備上或交易所的伺服器上,相對而言,會較傳統一些離線生成私鑰的方式被盜取或遺失的風險稍高,傳統的方式就是用一些非電子化的介質,例如可以將私鑰記錄在紙上,然後妥善收藏,這種也被稱作為"冷錢包",相對而言,比起主流方式,可以較大程度避免網絡上的攻擊或盜取,相對安全。
冷錢包的生成方式:而有些網站使用 Javascript 生成私鑰,例如 https://www.bitaddress.org,網站會根據鼠標在網頁上移動的軌跡,隨機運算出私鑰和錢包地址。為了避免在網絡傳輸中被截取數據,做法是將網頁另存成離線的頁面,然後放到一部離線的電腦上本地生成,然後將生成的私鑰和錢包地址打印出收藏好就可以。
Base64、Base58和Base58Check編碼
Base64編碼
Base64 編碼採用了 26 個小寫字母,26個大寫字母,10個數字及兩個符號("+"及"/"),主要為一種基於文本的二進制編碼格式。通常應用於編碼郵件中的附件及一些數據傳輸時的編碼。
從Base64編碼到Base58編碼
在加密貨幣和區塊鏈技術中,為了盡量壓縮數據及減少誤讀性,所以在 Base64 編碼的基礎上進行了精簡,省去了六個容易誤讀和容易混淆的字符,也得到了後來的 Base58 編碼。
Base58編碼
Base58 編碼是 Base64 編碼格式的子集,同樣是一種基於文本的二進制編碼格式,採用大小寫字母和數字,不過省去了六個容易誤讀和容易混淆的字符,增加了易讀性,同時對壓縮了數據。Base58 編碼不含 Base64 編碼中的0(數字0)、O(大寫字母o)、l(小寫字母L)、I(大寫字母i),以及「+」和「/」兩個字符組成。
省去這六個字符的原因是: 1. 避免混淆:數字0和字母大寫O,在某些字體下,以及字母大寫I和字母小寫l會非常相似; 2. 兼容性:"+"和"/"這些字符在一些作為帳號或內容很有可能不被系統所接受; 3. 增加可傳播性:為了增加傳播性,方便容易選擇和複製整個字符串,所以在Base58 編碼的字符集內並沒有標點符號,而且是連續的。
Base58 編碼的字符集:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
從Base58到Base58Check編碼
Base58Check 編碼是基於 Base58編碼的一種編碼格式,常用於比特幣中,在 Base58編碼上增加了4個字節的錯誤校驗碼,用於檢查數據在轉錄中出現的錯誤。是添加到需要編碼的數據之後。校驗碼是從需要編碼的數據的哈希值中得到的,所以可以用來檢測並避免轉錄和輸入中產生的錯誤。使用Base58Check編碼格式時,編碼軟件會計算原始數據的校驗碼並和結果數據中自帶的校驗碼進行對比。二者不匹配則表明有錯誤產生,亦即這個數據是無效的。例如,一個錯誤比特幣地址就不會被錢包認為是有效的地址,否則這種錯誤會造成資金的丟失。
為了使用Base58Check 編碼格式對數據進行編碼,要對數據添加一個稱作「版本字節」的前綴,這個前綴用來明確需要編碼的數據的類型。 例如,比特幣地址的前綴是0(十六進制是0x00),而對私鑰編碼時前綴是128(十六進制是0x80)。
以上介紹了私鑰、公鑰、錢包、Base58編碼、錢包地址,接下來,就是介紹這幾個之間的關係及它們的生成流程。
私鑰、公鑰、錢包地址的生成流程
如何從私鑰到公鑰,再從公鑰到錢包地址,具體生成的流程有幾下這些步驟:
- 生成隨機私鑰;比特幣客戶端一般會使用作業系統底層且被⼀個密碼學安全的隨機源初始化後的隨機數生成器來生成一串256位(bits)的熵,也可以使用上面提到的離線生成的方式,以確保是隨機生成的數。生成了一個數後,要先檢查它是否小於 n-1 (n是一個常數,為1.158*1077,略小於2^256),如果不小於 n-1,就要再重新隨機生成這個數,直至小於 n-1,得到私鑰:
KzCiehi5pTy9kqH6p7XBxjSvVPLSCsKWedJhGJXXTH7n849kumBC
接下來就對它進行以十六進制的形式表示
59007BB62BF6430A51DF4BC51726F22FBD2ACE8A773CF2728B7D3EC9C3A51CCC
- 從私鑰透過橢圓曲線算法得出公鑰;根據上面提及到的橢圓曲線算法(ECDSA-SECP256K1)計算出上面私鑰對應的(x,y),從而計算出非壓縮公鑰:公鑰 X值:
61BA5FF1B402ED585D2CFAAE9AEB1BA388CCDA425E73CF5748D5288015DB6B3F
公鑰 Y值:
111BEF04260287C0F248C5AAED776CF29897286DE831504293EB87F13CA16FA5
然後首位加上0x04,接合公鑰的X值及Y值,得到完整非壓縮公鑰:
0461BA5FF1B402ED585D2CFAAE9AEB1BA388CCDA425E73CF5748D5288015DB6B3F111BEF04260287C0F248C5AAED776CF29897286DE831504293EB87F13CA16FA5
而壓縮後的公鑰為:
0361BA5FF1B402ED585D2CFAAE9AEB1BA388CCDA425E73CF5748D5288015DB6B3F
- 使用 SHA-256 及 RIPEMD-160 計算出公鑰的 Hash值;使用 SHA-256計算出公鑰的 Hash值:
01EE39A5B0D20272059100256AF50EEA9F7BF2C10D7E63F44AAA33F64AD84F9F
使用 RIPEMD-160 及上面的 Hash值,計算出 Hash值:
B2A05990A7DECC25131E171ED42B85B11B410931
- 加入地址版本號(比特幣主網版本號「0x00」);在上面經過 RIPEMD-160 計算出的 Hash值前面加上16進制的00,因為比特幣主網版本號是"0x00"
00B2A05990A7DECC25131E171ED42B85B11B410931
- 進行兩次 SHA-256 計算出 Hash值;
2B4A93CF4E61C87CEA548E8061D0D17344B8B2AB0CD2EC60F31FEF4ED9B9C1B8 257F8E68F31EF143D0D68A72ED5C2D14080FDD953FD2A5E44C9114FA4601E666
- 把第5步的Hash前8位加到第4步的Hash值後面;這個步驟主要是在後面加上壓縮標誌和附加校驗碼(CheckSum,即對私鑰進行2次SHA-256運算,取結果的前4個位元)
00B2A05990A7DECC25131E171ED42B85B11B410931257f8e68
- 使用 Base58編碼轉換成錢包地址;經過轉換後的錢包地址(壓縮),亦即是
1HHVNT5dZxApCiGG1jjmgJ9LxCsei3PSLf
經過以上的流程,可以得知私鑰、公鑰和錢包地址之間,以及橢圓曲線算法、Base58、Base58Check、SHA-256之間的關係,從私鑰可以算出公鑰,公鑰經過計算運可以得出錢包地址,所以私鑰非常非常重要,一定要小心保管。由於橢圓曲線算法的不可逆,所以要反過來從公鑰推算出私鑰,目前來說都是不可能的,不過,可以透過 Base58反編碼將錢包地址反推算出公鑰的 Hash值。
參考網址
http://blog.csdn.net/hjm4702192/article/details/78552723
https://www.jinse.com/news/bitcoin/25035.html
您好,想請教一個問題:
在「私鑰、公鑰、錢包地址的生成流程」這段落中,最後一段話為:「生成了一個數後,要先檢查它是否小於 n-1 (n是一個常數,為1.158*1077,略小於2^256),如果不小於 n-1,就要再重新隨機生成這個數,直至小於 n-1,得到私鑰:KzCiehi5pTy9kqH6p7XBxjSvVPLSCsKWedJhGJXXTH7n849kumBC」
這部分是否漏寫中間的,先生成隨機數並檢查是否小於n-1,若小於則才使用sha-256產生上述的私鑰?不知這樣是否正確?或者,我哪部分迷失掉了?謝謝。
您好,在前一陣子,因受詐術誆騙投資管道,想將遭侵佔的比特幣取回,有辦法查得錢包地址的所有人嗎,若有請問建議如何做反查,感謝您!
@若被侵佔了比特幣,想反向追查 想知道 +1
寫得真好!
學到很多謝謝
也可以參考看看比特幣錢包喔!