理解開發HD 錢包涉及的 BIP32、BIP44、BIP39

Tiny熊發表於2018-09-29

最新內容會更新在主站深入淺出區塊鏈社群
原文連結:理解開發HD 錢包涉及的 BIP32、BIP44、BIP39

如果你還在被HD錢包、BIP32、BIP44、BIP39搞的一頭霧水,來看看這邊文章吧。

數字錢包概念

錢包用來存錢的,在區塊鏈中,我們的數字資產都會對應到一個賬戶地址上, 只有擁有賬戶的鑰匙(私鑰)才可以對資產進行消費(用私鑰對消費交易簽名)。
私鑰和地址的關係如下:理解開發HD 錢包涉及的 BIP32、BIP44、BIP39
(圖來自精通比特幣)
一句話概括下就是:私鑰通過橢圓曲線生成公鑰, 公鑰通過雜湊函式生成地址,這兩個過程都是單向的。
因此實際上,數字錢包實際是一個管理私鑰(生成、儲存、簽名)的工具,注意錢包並不儲存資產,資產是在鏈上的。

如何建立賬號

建立賬號關鍵是生成一個私鑰, 私鑰是一個32個位元組的數, 生成一個私鑰在本質上在1到2^256之間選一個數字
因此生成金鑰的第一步也是最重要的一步,是要找到足夠安全的熵源,即隨機性來源,只要選取的結果是不可預測或不可重複的,那麼選取數字的具體方法並不重要。
比如可以擲硬幣256次,用紙和筆記錄正反面並轉換為0和1,隨機得到的256位二進位制數字可作為錢包的私鑰。
從程式設計的角度來看,一般是通過在一個密碼學安全的隨機源(不建議大家自己去寫一個隨機數)中取出一長串隨機位元組,對其使用SHA256雜湊演算法進行運算,這樣就可以方便地產生一個256位的數字。

實際過程需要比較下是否小於n-1(n = 1.158 * 10^77, 略小於2^256),我們就有了一個合適的私鑰。否則,我們就用另一個隨機數再重複一次。這樣得到的私鑰就可以根據上面的方法進一步生成公鑰及地址。

BIP32

錢包也是一個私鑰的容器,按照上面的方法,我們可以生成一堆私鑰(一個人也有很多賬號的需求,可以更好保護隱私),而每個私鑰都需要備份就特別麻煩的。

最早期的比特幣錢包就是就是這樣,還有一個暱稱:“Just a Bunch Of Keys(一堆私鑰)“

為了解決這種麻煩,就有了BIP32 提議: 根據一個隨機數種子通過分層確定性推導的方式得到n個私鑰,這樣儲存的時候,只需要儲存一個種子就可以,私鑰可以推匯出來,如圖:
理解開發HD 錢包涉及的 BIP32、BIP44、BIP39
(圖來自精通比特幣)上圖中的孫祕鑰就可以用來簽發交易。

補充說明下 BIP: Bitcoin Improvement Proposals 比特幣改進建議, bip32是第32個改進建議。
BIP32提案的名字是:Hierarchical Deterministic Wallets, 就是我們所說的HD錢包。
來分析下這個分層推導的過程,第一步推導主祕鑰的過程:
理解開發HD 錢包涉及的 BIP32、BIP44、BIP39
根種子輸入到HMAC-SHA512演算法中就可以得到一個可用來創造主私鑰(m) 和 一個主鏈編碼( a master chain code)這一步生成的祕鑰(由私鑰或公鑰)及主鏈編碼再加上一個索引號,將作為HMAC-SHA512演算法的輸入繼續衍生出下一層的私鑰及鏈編碼,如下圖:理解開發HD 錢包涉及的 BIP32、BIP44、BIP39
衍生推導的方案其實有兩個:一個用父私鑰推導(稱為強化衍生方程),一個用父公鑰推導。同時為了區分這兩種不同的衍生,在索引號也進行了區分,索引號小於2^31用於常規衍生,而2^31到2^32-1之間用於強化衍生,為了方便表示索引號i',表示2^31+i。
因此增加索引(水平擴充套件)及 通過子祕鑰向下一層(深度擴充套件)可以無限生成私鑰。
注意, 這個推導過程是確定(相同的輸入,總是有相同的輸出)也是單向的,子金鑰不能推匯出同層級的兄弟金鑰,也不能推出父金鑰。如果沒有子鏈碼也不能推匯出孫金鑰。現在我們已經對分層推導有了認識。
一句話概括下BIP32就是:為了避免管理一堆私鑰的麻煩提出的分層推導方案。

祕鑰路徑及BIP44

通過這種分層(樹狀結構)推匯出來的祕鑰,通常用路徑來表示,每個級別之間用斜槓 / 來表示,由主私鑰衍生出的私鑰起始以“m”打頭。因此,第一個母金鑰生成的子私鑰是m/0。第一個公共鑰匙是M/0。第一個子金鑰的子金鑰就是m/0/1,以此類推。
BIP44則是為這個路徑約定了一個規範的含義(也擴充套件了對多幣種的支援),BIP0044指定了包含5個預定義樹狀層級的結構:
m / purpose' / coin' / account' / change / address_index
m是固定的, Purpose也是固定的,值為44(或者 0x8000002C)
Coin type
這個代表的是幣種,0代表比特幣,1代表比特幣測試鏈,60代表以太坊
完整的幣種列表地址:https://github.com/satoshilabs/slips/blob/master/slip-0044.md
Account
代表這個幣的賬戶索引,從0開始
Change
常量0用於外部鏈,常量1用於內部鏈(也稱為更改地址)。外部鏈用於在錢包外可見的地址(例如,用於接收付款)。內部鏈用於在錢包外部不可見的地址,用於返回交易變更。 (所以一般使用0)
address_index
這就是地址索引,從0開始,代表生成第幾個地址,官方建議,每個account下的address_index不要超過20
根據 EIP85提議的討論以太坊錢包也遵循BIP44標準,確定路徑是m/44'/60'/a'/0/n
a 表示帳號,n 是第 n 生成的地址,60 是在 SLIP44 提案中確定的以太坊的編碼。所以我們要開發以太坊錢包同樣需要對比特幣的錢包提案BIP32、BIP39有所瞭解。
一句話概括下BIP44就是:給BIP32的分層路徑定義規範

BIP39

BIP32 提案可以讓我們儲存一個隨機數種子(通常16進位制數表示),而不是一堆祕鑰,確實方便一些,不過使用者使用起來(比如冷備份)也比較繁瑣,這就出現了BIP39,它是使用助記詞的方式,生成種子的,這樣使用者只需要記住12(或24)個單詞,單詞序列通過 PBKDF2 與 HMAC-SHA512 函式建立出隨機種子作為 BIP32 的種子。
可以簡單的做一個對比,下面那一種備份起來更友好:

// 隨機數種子
090ABCB3A6e1400e9345bC60c78a8BE7  
// 助記詞種子
candy maple cake sugar pudding cream honey rich smooth crumble sweet treat

使用助記詞作為種子其實包含2個部分:助記詞生成及助記詞推匯出隨機種子,下面分析下這個過程。

生成助記詞

助記詞生成的過程是這樣的:先生成一個128位隨機數,再加上對隨機數做的校驗4位,得到132位的一個數,然後按每11位做切分,這樣就有了12個二進位制數,然後用每個數去查BIP39定義的單詞表,這樣就得到12個助記詞,這個過程圖示如下:
理解開發HD 錢包涉及的 BIP32、BIP44、BIP39
(圖來源於網路)

助記詞推匯出種子

這個過程使用金鑰拉伸(Key stretching)函式,被用來增強弱金鑰的安全性,PBKDF2是常用的金鑰拉伸演算法中的一種。
PBKDF2基本原理是通過一個為隨機函式(例如 HMAC 函式),把助記詞明文和鹽值作為輸入引數,然後重複進行運算最終產生生成一個更長的(512 位)金鑰種子。這個種子再構建一個確定性錢包並派生出它的金鑰。
金鑰拉伸函式需要兩個引數:助記詞和鹽。鹽可以提高暴力破解的難度。 鹽由常量字串 "mnemonic" 及一個可選的密碼組成,注意使用不同密碼,則拉伸函式在使用同一個助記詞的情況下會產生一個不同的種子,這個過程圖示圖下:
理解開發HD 錢包涉及的 BIP32、BIP44、BIP39
(圖來源於網路)
校驗和地址是EIP-55中定義的對大小寫有要求的一種地址形式。

密碼可以作為一個額外的安全因子來保護種子,即使助記詞的備份被竊取,也可以保證錢包的安全(也要求密碼擁有足夠的複雜度和長度),不過另外一方面,如果我們忘記密碼,那麼將無法恢復我們的數字資產。

一句話概括下BIP39就是:通過定義助記詞讓種子的備份更友好

我為大家錄製了一個視訊:以太坊去中心化網頁錢包開發,從如何建立賬號開始,深入探索BIP32、BIP44、BIP39等提案,以及如何儲存私鑰、傳送離線簽名交易和Token。

小結

HD錢包(Hierarchical Deterministic Wallets)是在BIP32中提出的為了避免管理一堆私鑰的麻煩提出的分層推導方案。
而BIP44是給BIP32的分層增強了路徑定義規範,同時增加了對多幣種的支援。
BIP39則通過定義助記詞讓種子的備份更友好。

目前我們的市面上單到的以太幣、比特幣錢包基本都遵循這些標準。

最後推薦一個助記詞祕鑰生成器網站

歡迎來知識星球提問,星球內已經聚集了300多位區塊鏈技術愛好者。
深入淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術部落格。

相關文章