[譯] 數字貨幣錢包詳解

Xat_MassacrE發表於2018-04-27

「錢包」這個詞語在以太坊中表示的並不是它本來的意思。

巨集觀的講,錢包主要就是為使用者提供使用者介面的一個應用。它掌管著使用者的金錢,管理著金鑰和地址,追蹤賬戶餘額以及建立交易和簽名。除此之外,一些以太坊錢包還可以與智慧合約進行互動,例如代幣之類的。

而從一個程式設計師的角度更準確的講,「錢包」這個詞語指的就是儲存和管理金鑰和地址的系統。每一個「錢包」都有一個金鑰管理元件。而對於有些錢包來說,這就是錢包的全部。其他的大部分錢包都是「瀏覽器」,其實就是基於以太坊的去中心化應用的介面。所以這些各式各樣的「錢包」之間並沒有什麼明確的界限。

接下來讓我們先看一看錢包關於金鑰管理和私鑰容器部分的功能。

錢包技術總覽

在這個部分我們會總結用於構建使用者友好、安全以及靈活的以太坊錢包所需要的各種技術。

關於以太坊有一個最常見的誤解就是大部分人認為以太坊錢包包含以太坊和其他代幣。而實際上,錢包只包含金鑰。以太坊和其他代幣都被記錄在以太坊的區塊鏈中。使用者通過使用他們錢包中的金鑰對錢包簽名來控制代幣。所以從某種意義上講,以太坊錢包就是一個鑰匙串

提示

以太坊錢包只包含金鑰,而沒有以太坊和代幣。每一個使用者的錢包都包含金鑰。錢包就是包含公私鑰對的鑰匙串。使用者使用金鑰對交易簽名,以此來證明這些以太坊就是屬於他們的。而真正的以太坊則儲存在區塊鏈上。

目前主要有兩種型別的錢包,他們的區別就是所包含的金鑰之間是否有關聯。

第一種型別叫做非確定性錢包,它的每一個金鑰都是通過一個隨機數獨立生成的。金鑰之間相互沒有關聯。這種錢包也叫做 JBOK 錢包(來自 "Just a Bunch Of Keys")。

第二種錢包叫做確定性錢包,它所有的金鑰都來源於一個單獨的叫做種子的主金鑰。在這個錢包中所有的金鑰都相互關聯,並且任何擁有原始種子的人都可以將這些金鑰再生成一遍。這種確定性錢包會使用很多不同的金鑰派生方法。而其中使用最普遍的則是一種類似樹形結構的方法,這樣的錢包被稱為分層確定性或者 HD 錢包。

分層確定性錢包是通過一個種子來初始化的。而為了便於使用,種子會被編碼成英語單詞(或者其他語言的單詞),這些單詞被稱為助記詞

下面的章節將會在更高階的層面介紹這些技術。

非確定性(隨機)錢包

在第一個的以太坊錢包(以太坊預售時釋出的)中,錢包檔案會儲存一個單獨隨機生成的私鑰。然而這種錢包之後被確定性錢包取代了,因為這種錢包無法管理、備份以及匯入私鑰。但是隨機金鑰的缺點是,如果你生成了很多那麼你就要把它們全部拷貝下來。每一個金鑰都要備份,否則一旦錢包丟失,那些金鑰對應的資產也會丟失。進一步講,以太坊地址的隱私性會因為相互之間關聯的多筆交易和地址的重複使用而大大降低。一個型別-0 的非確定性錢包並不是一個好的選擇,尤其是當你為了避免地址的重複使用而不得不管理多個金鑰並不斷頻繁的備份它們時。

很多以太坊客戶端(包括 go-ethereum 和 geth)都會使用一個鑰匙串檔案,這是一個 JSON 編碼的檔案,而且它還包含一個單獨的(隨機生成的)私鑰,為了安全性,這個私鑰會通過一個密碼進行加密。這個 JSON 檔案就像下面這樣:

{
    "address": "001d3f1ef827552ae1114027bd3ecf1f086ba0f9",
    "crypto": {
        "cipher": "aes-128-ctr",
        "ciphertext": "233a9f4d236ed0c13394b504b6da5df02587c8bf1ad8946f6f2b58f055507ece",
        "cipherparams": {
            "iv": "d10c6ec5bae81b6cb9144de81037fa15"
        },
        "kdf": "scrypt",
        "kdfparams": {
            "dklen": 32,
            "n": 262144,
            "p": 1,
            "r": 8,
            "salt": "99d37a47c7c9429c66976f643f386a61b78b97f3246adca89abe4245d2788407"
        },
        "mac": "594c8df1c8ee0ded8255a50caf07e8c12061fd859f4b7c76ab704b17c957e842"
    },
    "id": "4fcb2ba4-ccdb-424f-89d5-26cce304bf9c",
    "version": 3
}
複製程式碼

鑰匙串格式使用的是Key Derivation Function (KDF),同時還被成為密碼拉伸演算法,這個演算法可以防止暴力破解、字典攻擊以及彩虹表攻擊。簡單來說就是私鑰並不是直接通過密碼簡單的進行加密的。相反,這個密碼是通過不斷的重複雜湊拉伸過的。這個雜湊函式會重複 262144 輪,這個數字就是鑰匙串 JSON 檔案中的 crypto.kdfparams.n 這個引數指定的。一個攻擊者試圖通過暴力破解的手段來破解密碼的話,那麼他需要為每一個可能的密碼執行 262144 輪雜湊,這樣對於一個足夠複雜和長度的密碼來說被破解幾乎是不可能的。

這裡還有一些軟體庫可以讀取和寫入鑰匙串格式,例如 JavaScript 的庫 keythereum:

github.com/ethereumjs/…

提示

除了一些簡單的測試之外,我們是不推薦使用非確定性錢包的。我們推薦使用的是擁有助記詞種子備份功能的基於行業標準的HD 錢包

確定性錢包(種子)錢包

確定性或者說「種子」錢包是指那些所有的私鑰都是通過一個普通的種子使用一個單向雜湊函式延伸而來的錢包。這個種子是結合一些其他的資料而隨機生成的數字,例如利用一個索引數字或者「鏈碼」(檢視HD 錢包(BIP-32/BIP-44)來派生出私鑰。在一個確定性錢包中,一個種子就足夠恢復出所有派生的金鑰,因此只需要在建立的時候做一次備份就可以了。同時,這個種子對於錢包來說也是可以匯入匯出的,可以讓所有使用者的金鑰在各種不同的錢包之間進行簡單的遷移。

HD 錢包 (BIP-32/BIP-44)

確定性錢包的開發就是為了可以簡單的從一個「種子」派生出很多個金鑰。而這種確定性錢包最高階的實現就是由比特幣的 BIP-32 標準定義的 HD 錢包。HD 錢包包含的金鑰來源於一個樹形的結構,例如一個父金鑰可以派生出一系列子金鑰,每一個子金鑰又可以派生出一系列孫子金鑰,不停的迴圈往復,沒有盡頭。這個樹形結構的示意圖如下:

HD wallet: a tree of keys generated from a single
seed

HD 錢包相對於隨機的(非確定性的)金鑰有兩個主要的優勢。一,樹形結構可以表達額外的組織意義,例如當一個子金鑰特定的分支用來接收轉入支付而另一個不同的分支可以接收轉出支付的改變。金鑰的分支也可以在一些共同的設定中被使用,例如可以分配不同的分支給部門、子公司、特定的函式或者不同的賬單類別。

第二個優勢就是使用者可以使用 HD 錢包在不利用相關私鑰的情況下建立一系列公鑰。這樣 HD 錢包就可以用來做一個安全的服務或者是一個僅僅用來觀察和接收的服務,而錢包本身卻沒有私鑰,所以它也無法花費資金。

種子和助記詞 (BIP-39)

HD 錢包對於管理多個金鑰和地址來說是一個很強力的機制。如果再結合一個從一系列英語單詞(或者其他語言的單詞)中建立種子的標準化方法的話,那麼通過錢包進行抄寫、匯出和匯入都變得更加簡單易用。這就是大家所熟知的由標準 BIP-39 定義的助記詞。今天,很多以太坊錢包(還有其他的數字貨幣錢包)都在使用這個標準來匯入匯出種子,並使用共同的助記詞來進行備份和恢復。

讓我們來從實踐的角度看一下。下面哪個種子在抄寫、紙上記錄以及閱讀障礙這幾個方面更優秀呢?

一個 16 進位制編碼的確定性錢包種子

FCCF1AB3329FD5DA3DA9577511F8F137
複製程式碼

一個由 12 個單片語成的助記詞的錢包種子

wolf juice proud gown wool unfair
wall cliff insect more detail hub
複製程式碼

錢包最佳實踐

隨著數字貨幣錢包技術的逐漸成熟,也慢慢形成了共同的行業標準,使得錢包在互動性、易用性、安全性和靈活性等方面大幅度提高。這些標準同時也使得錢包可以僅僅從一個單獨助記詞就為各種不同的數字貨幣派生出不同的金鑰。這些共同的標準就是下面這些:

  • 基於 BIP-39 的助記詞

  • 基於 BIP-32 的 HD 錢包

  • 基於 BIP-43 的多用途 HD 錢包結構

  • 基於 BIP-44 的多貨幣多賬戶錢包

這些標準或許會改變,也或許會被未來的開發者廢棄,但是現在它們組成的這一組連鎖技術儼然已經成為了大多數數字貨幣的實際上的錢包標準。

這些標準已經被大部分的軟體和硬體錢包所採用,使得這些錢包之間可以相互通用。一個使用者可以從這些錢包中的任意一個匯出助記詞,然後匯入到另一個錢包中,並恢復所以的交易、金鑰和地址。

很多軟體錢包都支援這種標準,例如(按字母 排序)Jaxx, MetaMask, MyEtherWallet (MEW)。硬體錢包則有 Keepkey, Ledger, and Trezor。

下面的章節會詳細講解這些技術。

提示

如果你要實現一個以太坊錢包,他應該是一個 HD 錢包,種子會被編碼成助記詞以供備份,BIP-32、BIP-39、BIP-43、和 BIP-44 這些標準會在下面的章節中詳細說明。

助記詞 (BIP-39)

助記詞就是代表一個隨機數的單詞序列,這個助記詞會作為種子派生出一個確定性錢包。這個序列的單詞能夠再次建立種子、錢包和所有派生出的金鑰。一個實現了確定性錢包助記詞功能的應用將會向在第一次建立錢包的時候向使用者展示一組長度為 12 到 24 的單詞序列。這個序列就是錢包的備份,它可以在任何相容的錢包上實現恢復和重建所有的金鑰。助記詞可以讓使用者更簡單的備份錢包,因為相比於一組隨機數助記詞可讀性更好,抄寫的正確率也更高。

提示

助記詞常常與「大腦錢包」想混淆。但是它們並不是一回事。而其中最主要的區別在於大腦錢包是由使用者自己選擇的單片語成的,而助記詞則是錢包代表使用者隨機建立的。這個重要的區別使得助記詞更加的安全,因為人類隨機性的來源少的可憐。

助記詞編碼是在 BIP-39 中定義的。注意 BIP-39 只是助記詞編碼的一個實現。還有很多不同的標準,比特幣錢包 Electrum 就是在 BIP-39 之前使用了一組不同的單詞。BIP-39 這個標準是由硬體錢包 Trezor 背後的公司提出來的,而且還相容 Electrum 的實現。但是,BIP-39 現在已經取得了廣泛的行業支援,並且相容十幾個相互操作的實現,所以 BIP-39 應該就是現在的行業標準。並且,BIP-39 可以用來生成支援以太坊的多貨幣錢包,而 Electrum 的種子並不支援。

BIP-39 標準定義了助記詞編碼和種子的生成過程,也就是接下來的九個步驟。為了表達的更清楚,整個過程分成了兩個部分:第一步到第六步在生成助記詞,第七步到第九步在助記詞到種子

生成助記詞

助記詞是錢包使用 BIP-39 中定義的標準化過程自動生成的。錢包起始於一個熵的源頭,然後新增一個校驗和並將熵對映到一個單詞陣列中。

  1. 建立一個 128 位到 256 位的隨機序列(熵)

  2. 通過取 SHA256 的前(熵長度除以 32)位來建立這個隨機序列的校驗和。

  3. 將校驗和新增到隨機序列的末尾。

  4. 將序列分成幾個 11 位的部分。

  5. 從預定義的 2048 個單詞字典中將每一個 11 位的值對映到一個單詞上面。

  6. 助記詞編碼就是一系列單詞。

生成熵並編碼成助記詞將會展示出熵是如何生成助記詞的。

Generating entropy and encoding as mnemonicwords

助記詞編碼:熵和單詞長度 展示出了熵資料的大小和單詞中助記詞長度的關係。

助記詞編碼: 熵(entropy)和單詞(word)長度
Entropy (bits) Checksum (bits) Entropy + checksum (bits) Mnemonic length (words)

128

4

132

12

160

5

165

15

192

6

198

18

224

7

231

21

256

8

264

24

從助記詞到種子

助記詞代表著長度為 128 到 256 位的熵。這個熵會通過金鑰拉伸函式 PBKDF2 生成一個更長的(512 位)種子。這個種子再構建一個確定性錢包並派生出它的金鑰。

金鑰拉伸函式需要兩個引數:助記詞和。鹽的目的是為了讓暴力破解構建查詢表的難度提高。在標準 BIP-39 中,鹽還有另外一個目的,那就是密碼可以作為一個額外的安全因子來保護種子,這部分會在BIP-39 中的可選密碼中詳細講述。

第七步到第九步的過程:

  1. 金鑰拉伸函式 PBKDF2 的第一個引數第六步中生成的助記詞。

  2. 金鑰拉伸函式 PBKDF2 的第二個引數就是。這個鹽由字串常量 "mnemonic" 和一個額外的使用者提供的密碼字串拼接構成。

  3. PBKDF2 使用 HMAC-SHA512 演算法進行了 2048 輪雜湊運算對助記詞和鹽進行拉伸,生成一個 512 位的值作為最後的輸出。這個 512 位的值就是種子。

[fig_5_7] 展示出了一個助記詞是如何生成種子的。

From mnemonic to seed

提示

金鑰拉伸函式以及它的 2048 輪雜湊從某種程度上講對於暴力破解助記詞和密碼是一個有效的保護。會讓其以昂貴的代價(在計算資源上)不停的嘗試成千上萬種密碼和助記詞的組合,而這些組合的數量則猶如汪洋大海(2512)。

下面的表格分別展示了 #mnemonic_128_no_pass、#mnemonic_128_w_pass 和 #mnemonic_256_no_pass 這幾個型別的助記詞和他們產生的種子(沒有密碼)的例子。

128 位(bit)熵(entropy)的助記詞編碼(mnemonic code),無密碼生成的種子(seed)

Entropy input (128 bits)

0c1e24e5917779d297e14d45f14e1a1a

Mnemonic (12 words)

army van defense carry jealous true garbage claim echo media make crunch

Passphrase

(none)

Seed (512 bits)

5b56c417303faa3fcba7e57400e120a0ca83ec5a4fc9ffba757fbe63fbd77a89a1a3be4c67196f57c39 a88b76373733891bfaba16ed27a813ceed498804c0570

128 位(bit)熵(entropy)的助記詞編碼(mnemonic code),有密碼生成的種子(seed)

Entropy input (128 bits)

0c1e24e5917779d297e14d45f14e1a1a

Mnemonic (12 words)

army van defense carry jealous true garbage claim echo media make crunch

Passphrase

SuperDuperSecret

Seed (512 bits)

3b5df16df2157104cfdd22830162a5e170c0161653e3afe6c88defeefb0818c793dbb28ab3ab091897d0 715861dc8a18358f80b79d49acf64142ae57037d1d54

256 位(bit)熵(entropy)的助記詞編碼(mnemonic code),無密碼生成的種子(seed)

Entropy input (256 bits)

2041546864449caff939d32d574753fe684d3c947c3346713dd8423e74abcf8c

Mnemonic (24 words)

cake apple borrow silk endorse fitness top denial coil riot stay wolf luggage oxygen faint major edit measure invite love trap field dilemma oblige

Passphrase

(none)

Seed (512 bits)

3269bce2674acbd188d4f120072b13b088a0ecf87c6e4cae41657a0bb78f5315b33b3a04356e53d062e5 5f1e0deaa082df8d487381379df848a6ad7e98798404

BIP-39 中的可選密碼

BIP-39 標準允許使用者在生成種子的時候使用可選密碼。如果沒有使用密碼,那麼助記詞就會被一個由常量字串 "mnemonic" 組成的鹽拉伸,然後由給定的助記詞產生一個特定的 512 位種子。如果使用了密碼,則拉伸函式在使用同一個助記詞的情況下會產生一個不同的種子。實際上,給定一個助記詞,每一個可能的密碼都會生成不同的種子。並且基本上沒有任何「錯誤」的 密碼。所有的密碼都是可用的並且所有的密碼都可以生成不同種子,這些不同的助記詞會形成一組數量巨大的為初始化的錢包。這些可能的錢包數量是如此之大 (2512),以至於實際情況中暴力破解和意外猜對的可能性幾乎為零,只要密碼擁有足夠的複雜度和長度。

提示

在標準 BIP-39 中不存在「錯誤的」密碼。每個密碼都會生成一個錢包,如果不是之前使用的密碼的話那就是一個新的錢包。

可選密碼會產生兩個重要的特性:

  • 一個需要記憶的第二個因子可以防止助記詞的備份被竊取。

  • 選擇密碼的這些貌似擁有可信拒絕能力或者說是「監禁的錢包」使得那些小額資金的錢包經常將攻擊者的注意力從那些「真正的」大額資金錢包中分散出來。

但是,需要注意的一點是使用密碼會面臨密碼丟失的風險。

  • 如果錢包的主人缺乏行動能力或者去世了,那麼就沒人知道密碼了,也沒人知道種子是什麼,那麼錢包中儲存的所有資金就全部丟失了。

  • 相反,如果錢包的主人在與種子同樣的地方備份了密碼,那麼它就失去了第二個因素的目的。

雖然密碼非常有用,但是也應該結合小心的計劃備份和恢復的過程來使用,因為要考慮到錢包主人生還的可能性並可以允許他們的家人來恢復數字貨幣的資產。

助記詞的工作

BIP-39 在很多不同的程式語言中都有實現的庫:

python-mnemonic
參考了 SatoshiLabs 團隊在 BIP-39 中提議的 Python 版本

Consensys/eth-lightwallet
用於節點和瀏覽器(基於 BIP-39)的輕量級 JS 以太坊錢包

npm/bip39
比特幣 BIP39 的 JavaScript 實現:用於生成確定性金鑰的助記詞編碼

還有一個在單獨的網頁中實現的 BIP-39 生成器,這個網頁在測試和實驗中非常有用。BIP-39 生成器展示了一個可以生成助記詞、種子以及擴充的私鑰的單獨的網頁。

A BIP-39 generator as a standalone web page

網頁(iancoleman.github.io/bip39/)可以在瀏覽器中離線使用(線上當然也可以)。

通過種子建立一個 HD 錢包

HD 錢包是通過一個根種子來建立的,這個根種子一般是 128、256 或者 512 位的隨機數。通常情況下,這個種子是通過一個助記詞來生成的。

HD 錢包中的每一個金鑰都是派生自這個根種子,這樣就使得通過這個種子在其他相容性錢包中重建整個 HD 錢包成為了可能。同時還使得備份、恢復、匯出以及匯入包含成千上萬個金鑰的錢包變的非常簡單,僅僅通過轉移從根種子派生出的助記詞就可以了。

[[bip32_bip43/44]] ==== 分層確定性錢包 (BIP-32) 和路徑 (BIP-43/44)

大多數 HD 錢包都遵循 BIP-32 標準,同時 BIP-32 也是確定金鑰生成器的實際上的行業標準。詳細的說明可以檢視下面的連結:

github.com/bitcoin/bip…

在這裡我們不會討論 BIP-32,我們只需要理解錢包中使用它的部分就可以了。在其他一些軟體庫中還有很多關於 BIP-32 彼此協作的實現。

Consensys/eth-lightwallet
用於節點和瀏覽器(基於 BIP-39)的輕量級 JS 以太坊錢包

這裡還有一個標準 BIP-32 的網頁版的生成器,對於測試和實驗都非常有用。

bip32.org/

提示

這個單獨的 BIP-32 生成器不是一個 HTTPS 的站點。就是為了告訴你使用這個工具不是安全的。只是用來做測試的。你不應該在生產環境中(真實的資金)使用這個網頁生成的金鑰。

擴充公鑰和私鑰

在 BIP-32 的術語中,一個父金鑰可以擴充的生成「兒子」,這個兒子就是擴充金鑰。如果它是一個私鑰,那麼它就是一個擴充私鑰,並通過字首 xprv 來區分:

xprv9s21ZrQH143K2JF8RafpqtKiTbsbaxEeUaMnNHsm5o6wCW3z8ySyH4UxFVSfZ8n7ESu7fgir8imbZKLYVBxFPND1pniTZ81vKfd45EHKX73
複製程式碼

一個擴充公鑰通過字首 xpub 來區分:

xpub661MyMwAqRbcEnKbXcCqD2GT1di5zQxVqoHPAgHNe8dv5JP8gWmDproS6kFHJnLZd23tWevhdn4urGJ6b264DfTGKr8zjmYDjyDTi9U7iyT
複製程式碼

HD 錢包中一個非常有用的角色就是從父公鑰派生出子公鑰,不包含私鑰。這會給我們提供兩種方法來派生子公鑰:從子私鑰或者直接從父公鑰來派生。

一個擴充公鑰可以在 HD 錢包的結構中派生出所有的公鑰(也只能是公鑰)。

無論什麼情況只要部署的服務和應用有一份擴充公鑰並且沒有私鑰,那麼這個快捷方式就可以建立非常安全的公鑰。這種部署可以生成無窮個公鑰和以太坊地址,但是卻不能花費任何傳送到這些地址的資金。同時,在另外一個更安全的伺服器上,擴充私鑰可以派生出所有相關的私鑰用來給交易簽名,並花費資金。

利用這種解決方案的一個常見的應用就是在一個 web 伺服器上安裝一個擴充公鑰,來為電子商務應用服務。這個網頁伺服器可以使用公鑰派生函式為每一筆交易(例如客戶的購物車)創造出一個全新的以太坊地址。這個網頁伺服器沒有任何私鑰所以盜賊也無法竊取。不使用 HD 錢包的情況下,想做到這個程度唯一的方法就是在一個分割的安全伺服器上生成上千個以太坊地址然後在電子商務伺服器上預載入他們。這個方法低效笨重,並且需要經常的維護以確保電子商務伺服器不會洩露金鑰。

還有一個常見的應用就是冷儲存和硬體錢包。在這種場景下,擴充私鑰可以儲存在硬體錢包中,但是擴充公鑰可以放線上上。使用者可以按照他們的意願建立接收的地址,私鑰則會離線安全的儲存。想花掉裡面的資金的話,使用者可以在離線簽名的以太坊客戶端或者支援交易簽名的硬體錢包上使用擴充私鑰。

硬化金鑰派生

從 xpub 中派生出一個公鑰分支的能力時很有用的,但同時也是具有風險的。知道 xpub 並不意味著知道子金鑰。然而,因為 xpub 包含鏈碼,所以如果一個子金鑰被別人知道或者暴露了的話,那麼它就可以和鏈碼一起派生出所有其他的子金鑰。一個單獨洩露的子金鑰和一個父鏈碼一起可以暴露出所有的子私鑰。而更糟糕的是,子私鑰和父鏈碼一起還可以推斷出父私鑰。

為了避免這個風險,HD 錢包使用了另外一種叫做硬化派生的派生函式,這個函式可以「破壞」父公鑰和子鏈碼的聯絡。這種硬化派生函式是使用父私鑰來派生出子鏈碼的,而不是父公鑰。這樣會在父或子序列中創造出一個「防火牆」,而這個防火牆並不會威脅到父或者子私鑰的安全。

簡單的來說就是,如果不想承受洩露你自己鏈碼風險,並且還想要方便的使用 xpub 來派生出公鑰分支,那麼你應該通過硬化父輩來派生它,而不是一個正常的父輩。這其中的最佳實踐就是,為了防止威脅到主要的金鑰,主要金鑰的 level-1 子輩總是通過硬化派生來派生。

正常派生和硬化派生的指數

BIP-32 中的派生函式使用的是一個 32 位整型的指數。為了方便的區分出正常派生函式和硬化派生函式生成的金鑰,這個指數分成了兩個區間。0 到 231–1 (0x0 to 0x7FFFFFFF) 用來表示正常的派生。231 到 232–1 (0x80000000 to 0xFFFFFFFF) 用來表示硬化派生。因此,如果指數小於 231,則子輩是正常的,如果指數大於等於 231,那麼子輩就是硬化的。

為了讓指數的易讀性和顯示性更好,硬化子輩的指數是從零開始顯示的(有一個素數符合)。第一個正常子金鑰則顯示為 0,這樣第一個硬化子輩(指數為 0x80000000)就會顯示為 0'。而第二個硬化金鑰指數從 0x80000001 開始,並且顯示為1',以此類推。當你看到一個 HD 錢包的指數為 i' 時,就意味著 231+i。

HD 錢包金鑰識別符號(路徑)

一個 HD 錢包中的金鑰是通過「路徑」命名規則來標識的,對於樹的每一個層級都通過斜槓 (/) 這個字元來分隔(檢視HD 錢包路徑示例)。 從主私鑰派生出的私鑰都以 "m." 開頭。從主公鑰派生出的公鑰以 "M." 開頭。因此主私鑰的第一個子私鑰就是 m/0。主公鑰的第一個子公鑰就是 M/0。第一個子輩的第二個孫子就是 m/0/1,以此類推。

一個金鑰的「祖先」是從右向左讀取的,直到派生出它本身的主金鑰為止。舉個例子,識別符號 m/x/y/z 就是 m/x/y 的第 z 個子金鑰、m/x 的第 y 個子金鑰、m 的第 x 個子金鑰。

HD 錢包路徑示例
HD path Key described

m/0

主私鑰 m 的第一個(0)兒子私鑰

m/0/0

第一個子輩(m/0)的第一個孫子私鑰

m/0'/0

第一個硬化子輩 (m/0') 的第一個標準孫子

m/1/0

第二個子輩(m/1)的第一個孫子私鑰

M/23/17/0/0

第 24 個子輩的第 18 個孫子輩的第一個曾孫輩的第一個玄孫的公鑰

HD 錢包的樹形結構指南

HD 錢包的樹形結構提供了巨大的靈活性。每一個父擴充金鑰都可以擁有 40 億個子輩:20 億個普通子輩和 20 億個硬化子輩。每一個子輩都有另外 40 億個子輩,以此類推。只要你想,這個樹形結構就可以一代一代的無限延伸下去。但是這種靈活性又使得對這個無限的樹形結構操作變的複雜。尤其是在各種實現之間轉移 HD 錢包變的尤為困難,因為這個內部的結構從分支到子分支的可能性是無限的。

現在的兩種 BIP 都是通過對 HD 錢包的樹形結構建立一些標準來解決這些複雜性的。BIP-43 提議將第一個硬化子指數作為可以表示樹形結構「用途」的特殊識別符號。而 BIP-43 則認為,HD 錢包應該只使用一個樹形結構 level-1 的分支,並通過定義它的用途來讓指數來標識結構以及剩餘數的名稱空間。例如,一個 HD 錢包只使用分支 m/i'/,並打算使用它來指明一個特殊的用途,而這個用途就是用指數 "i" 來標識的。

再說明一下這個細則,BIP-44 提議的多貨幣多賬戶的結構就是 BIP-43 的「用途」數字 44'。所有的 HD 錢包都遵循 BIP-44 結構,這個結構就是實際中使用樹形結構一個分支 m/44'/ 所標識的結構。

BIP-44 還指明瞭五個預定義的樹層級:

m / purpose' / coin_type' / account' / change / address_index
複製程式碼

第一個層級 "purpose" 一直等於 44'。第二個層級 "coin_type" 指明瞭數字貨幣的型別,對於多貨幣的 HD 錢包來每一個種貨幣都在第二層級下有他自己的子樹。這裡有幾個在標準文件中定義的貨幣,叫作 SLIP0044:

github.com/satoshilabs…

舉個例子:以太坊是 m/44'/60',以太經典是 m/44'/61',比特幣是 m/44'/0',所有這些貨幣的測試網路都是 m/44'/1'。

第三個層級是 "account",它允許使用者把他們的錢包再分成幾個邏輯子賬戶,用於會計或者組織的目的。舉例來說,一個 HD 錢包可以包含兩個以太坊「賬戶」:m/44'/60'/0' 和 m/44'/60'/1'。而每個帳戶都是它自己子樹的根。

因為 BIP-44 一開始是為比特幣創造的,所以它包含的 "quirk" 和以太坊一點關係都沒有。路徑的第四層級是 "change",一個 HD 錢包有兩個子樹,一個用來建立接收地址,一個用來建立改變地址。而以太坊中只有「接收」地址,並不需要改變地址。注意,由於上個層級使用了硬化派生,所以這個層級就是普通派生。這是為了讓這個層級的樹可以在非安全環境下匯出可以使用的公鑰。可用的地址由 HD 錢包派生出來作為第四層級的子輩,然後形成樹第五層級的 "address_index"。舉例來說就是,以太坊的第三個接收地址在主賬戶中的支付將會是 M/44'/60'/0'/0/2。BIP-44 HD 錢包的結構示例

BIP-44 HD 錢包結構示例
HD 路徑 金鑰描述

M/44'/60'/0'/0/2

主以太坊賬戶的第三個收到的公鑰

M/44'/0'/3'/1/14

第四個比特幣賬戶的第 15 個可變地址的公鑰

m/44'/2'/0'/0/1

用於簽名交易的萊特幣主賬戶的第二個私鑰

掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章