HD 錢包及其建立過程的精華總結
引子
建立錢包及其重要的幾個都寫完了,但總感覺還缺少一些什麼,到底缺少什麼呢?在重新讀過幾邊之後,才發現通過前面幾篇文章還是不能把一切連貫起來,所以又補寫了本篇,作為建立錢包的補充說明。
正文
首先說明,下文中說的hash160 字串
指的是私鑰或公鑰的內容通過雙重雜湊演算法(行
SHA256
,再
RIPEMD160
)生成的長度為 20 個位元組的字串。
錢包是 keystore 的擴充套件,管理著交易和餘額,提供建立交易的能力。它有幾個特別重要的屬性,現在解釋如下:
- hdChain,HD 資料模型,它包含了一個 hash160 的種子,一個內部鏈的數量和一個外部鏈的數量。
- setInternalKeyPool,內部金鑰池的集合。
- setExternalKeyPool,外部金鑰池的集合。
- set_pre_split_keypool,一個預分割的金鑰池集合。
- m_max_keypool_index,最大金鑰池的索引。
- m_pool_key_to_index
- mapKeyMetadata,公鑰元資料的對映集合。鍵為一個 hash160 字串,值為一個公鑰元資料。
- m_script_metadata
- mapMasterKeys,
- mapWallet
- mapAddressBook
錢包說完了,我們來看 keystore。keystore 顧名思議它代表了金鑰的儲存,自然而然提供了一些管理金鑰的方法,比如:新增一個金鑰(私鑰和公鑰)到 store中、檢查給定地址對應的金鑰是否在 store中、新增及檢查一般指令碼與只讀指令碼的功能等。根據是否加密,keystore 分為基礎的和加密的兩種。錢包繼承自加密的 keystore,而加密的 keystore 又繼承了基礎的 keystore。
我們先來看下 基礎 keystore ,它有以下幾個重要的屬性:
- mapKeys,一個私鑰對映集合。鍵為一個 hash160 字串,值為一個私鑰。
- mapWatchKeys,一個只讀的公鑰對映集合。鍵為一個 hash160 字串,值為一個公鑰。
- mapScripts,一個指令碼對映集合。鍵為一個 hash160 字串,值為一個用在交易輸入和輸出的序列化的指令碼。
- setWatchOnly,一個用在交易輸入和輸出的序列化的指令碼集合。
加密 keystore 在基礎 keystore 上增加了幾個與加密相關的屬性,它們分別為:
- fUseCrypto,一個標誌錢包是否為加密的變數。
- vMasterKey,一個在加密情況下使用的私鑰集合。當加密時
mapKeys
集合就會為空,而vMasterKey
集合不空;當不加密時,情況正好反過來,即mapKeys
集合不空,而vMasterKey
集合為空。 - mapCryptedKeys,一個對映集合。鍵為一個 hash160 字串,值為一個公鑰和加密後私鑰組成的 pair 。
fInternal
、
m_pre_split
,前者表示金鑰池是內部還是外部的,後者功能暫時不清楚,英語備註為:For keys generated before keypool split upgrade。
m_pre_split
屬性預設為假。
當建立錢包時,會執行如下幾個動作:
- 首先,生成一個私鑰,根據私鑰通過橢圓曲線演算法生成對應的公鑰;
- 其次,也會生成對應的金鑰元資料,並且把公鑰的內容用 hash160 (先 SHA256,再RIPEMD160)演算法生成的 20個位元組的字串儲存為金鑰元資料的種子,然後把私鑰元資料儲存在
mapKeyMetadata
集合中; - 然後,私鑰被儲存在
mapKeys
,或mapCryptedKeys
與vMasterKey
集合中;當公鑰是壓縮的(通常是)時,通過公鑰生成指令碼,指令碼進而被儲存在mapScripts
集合中;同時,私鑰、公鑰及金鑰元資料都被儲存在資料庫中。 - 再然後,公鑰被作為種子,生成 HD 鏈物件,儲存在錢包中。
- 最後,當前面一切完成後,使用前面 3步生成的公鑰做為種子,開始衍生使用者指定數量的子私鑰/公鑰對,如果使用者沒有指定則預設衍生 3000 個子私鑰/公鑰對。
- 衍生的私鑰、公鑰及元資料的處理與第 2、3 步相同;
- 同時,用公鑰生成的金鑰池也被儲存在資料庫中;
- 根據生成的私鑰屬於內部或外部,對應的索引儲存在
setInternalKeyPool
、或setExternalKeyPool
集合中;不區分地,索引被儲存在m_pool_key_to_index
對映集合中,其中鍵為公鑰對應的 hash160 字串。
其中,2000 個子私鑰的路徑從
m/0'/0'/0
到m/0'/0'/1999
,1000 個子私鑰的路徑從m/0'/1'/0
到m/0'/1'/999
。其中的m
代表私鑰,m/0'
代表主私鑰的第 1 個強化子私鑰,m/0'/0'/0
代表主私鑰的第 1 個強化子私鑰的外部鏈的第 1 個強化孫私鑰,同理,m/0'/0'/1999
代表主私鑰的第 1 個強化子私鑰的外部鏈的第 1999 個強化孫私鑰;m/0'/1'/0
代表主私鑰的第 1 個強化子私鑰的內部鏈的第 1 個強化孫私鑰,同理,m/0'/1'/999
代表主私鑰的第 1 個強化子私鑰的內部鏈的第 999 個強化孫私鑰。
GenerateNewSeed
方法的主要內容,第 4 步是
SetHDSeed
的主要內容,第 5 步是
TopUpKeyPool
的主要內容。
最後,用兩張圖來概述 HD 錢包的建立。


後記
由於本人水平所限,文中錯誤在所難免,歡迎您踴躍指出錯誤,在下感激不盡。我的微信聯絡方式:joepeak。