https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
RECENT CHANGES:
- (16 Apr 2013) Added private derivation for i ≥ 0x80000000 (less risk of parent private key leakage)
- (30 Apr 2013) Switched from multiplication by IL to addition of IL (faster, easier implementation)
- (25 May 2013) Added test vectors
- (15 Jan 2014) Rename keys with index ≥ 0x80000000 to hardened keys, and add explicit conversion functions.
- (24 Feb 2017) Added test vectors for hardened derivation with leading zeros
BIP: 32 Layer: Applications Title: Hierarchical Deterministic Wallets Author: Pieter Wuille <pieter.wuille@gmail.com> Comments-Summary: No comments yet. Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0032 Status: Final Type: Informational Created: 2012-02-11 License: BSD-2-Clause
BIP 32定義了HD wallet,是一個系統可以從單一個 seed 產生一樹狀結構儲存多組 keypairs(私鑰和公鑰)。好處是可以方便的備份、轉移到其他相容裝置(因為都只需要 seed),以及分層的權限控制等。
Abstract
This document describes hierarchical deterministic wallets (or "HD Wallets"): wallets which can be shared partially or entirely with different systems, each with or without the ability to spend coins.
The specification is intended to set a standard for deterministic wallets that can be interchanged between different clients. Although the wallets described here have many features, not all are required by supporting clients.
The specification consists of two parts. In a first part, a system for deriving a tree of keypairs from a single seed is presented. The second part demonstrates how to build a wallet structure on top of such a tree.
這個文檔描述了HD Wallets,它能夠部分或完整地在不同系統使用,每一個都可以有/沒有發送貨幣的能力。
它的目的就是設置一個能夠讓HD Wallets在不同的用戶間交互的標准。雖然這里描述這個wallet有很多特性,但是並不是所有的都需要提供給用戶
該規范包含兩部分。第一部分是一個可以從已有的單一個 seed 產生一樹狀結構儲存多組 keypairs(私鑰和公鑰)的系統。第二部分是闡述如何在該樹狀結構上創建一個wallet結構。
Motivation
The Bitcoin reference client uses randomly generated keys. In order to avoid the necessity for a backup after every transaction, (by default) 100 keys are cached in a pool of reserve keys. Still, these wallets are not intended to be shared and used on several systems simultaneously. They support hiding their private keys by using the wallet encrypt feature and not sharing the password, but such "neutered" wallets lose the power to generate public keys as well.
Deterministic wallets do not require such frequent backups, and elliptic curve mathematics permit schemes where one can calculate the public keys without revealing the private keys. This permits for example a webshop business to let its webserver generate fresh addresses (public key hashes) for each order or for each customer, without giving the webserver access to the corresponding private keys (which are required for spending the received funds).
However, deterministic wallets typically consist of a single "chain" of keypairs. The fact that there is only one chain means that sharing a wallet happens on an all-or-nothing basis. However, in some cases one only wants some (public) keys to be shared and recoverable. In the example of a webshop, the webserver does not need access to all public keys of the merchant's wallet; only to those addresses which are used to receive customer's payments, and not for example the change addresses that are generated when the merchant spends money. Hierarchical deterministic wallets allow such selective sharing by supporting multiple keypair chains, derived from a single root.
比特幣客戶端使用隨機生成的密鑰。為了避免每次交易后都需要備份,(默認情況下)將100個keys緩存在備用keys池中.不過,這些錢包不打算被共享,並同時在多個系統上使用.他們支持使用錢包加密功能隱藏私鑰,而不共享密碼,但這種“neutered”錢包也失去了生成公鑰的能力。
HD錢包不需要如此頻繁的備份,而橢圓曲線數學允許在不暴露私鑰的情況下計算公鑰的方案.例如,webshop業務允許它的webserver為每個訂單或每個客戶生成新的地址(公鑰散列),而不允許webserver訪問相應的私鑰(用於支出收到的資金)。
然而,HD錢包通常由一個“鏈”keypairs組成。只有一條鏈的事實意味着共享一個錢包發生在0或1的基礎上,即要么keys都不共享,要么共享全部keys.但是,在某些情況下,您只需要一些(公共)密鑰來共享和恢復.比如在webshop的例子中,webserver不需要訪問商家錢包的所有公鑰;只需要那些用於接收客戶付款的地址,而不是商家花錢時生成的更改地址。HD錢包通過支持從單個根派生的多個密鑰對鏈,允許這樣的選擇性共享。
Specification: Key derivation
Conventions
In the rest of this text we will assume the public key cryptography used in Bitcoin, namely elliptic curve cryptography using the field and curve parameters defined by secp256k1 (http://www.secg.org/sec2-v2.pdf). Variables below are either:
在本文的其余部分中,我們將假設使用的是比特幣中使用的公鑰密碼,即使用secp256k1定義的字段和曲線參數的橢圓曲線密碼
- Integers modulo the order of the curve (referred to as n).
- Coordinates of points on the curve.
- Byte sequences.
Addition (+) of two coordinate pair is defined as application of the EC group operation. Concatenation (||) is the operation of appending one byte sequence onto another.
As standard conversion functions, we assume標准轉換函數:
- point(p): returns the coordinate pair resulting from EC point multiplication (repeated application of the EC group operation) of the secp256k1 base point with the integer p.返返回由整數p表示的secp256k1基點的EC點乘法(EC組操作的重復應用)產生的坐標對
- ser32(i): serialize a 32-bit unsigned integer i as a 4-byte sequence, most significant byte first.將一個32位無符號整數i序列化為一個4字節的序列,大端存儲
- ser256(p): serializes the integer p as a 32-byte sequence, most significant byte first.將整數p序列化為32字節序列,大端存儲
- serP(P): serializes the coordinate pair P = (x,y) as a byte sequence using SEC1's compressed form: (0x02 or 0x03) || ser256(x), where the header byte depends on the parity of the omitted y coordinate.使用SEC1的壓縮形式(0x02或0x03)|| ser256(x)將坐標對P = (x,y)序列化為字節序列,其中header字節取決於省略的y坐標的奇偶校驗。
- parse256(p): interprets a 32-byte sequence as a 256-bit number, most significant byte first.將32字節序列轉成256位的數字,大端存儲
Extended keys擴展密鑰
In what follows, we will define a function that derives a number of child keys from a parent key. In order to prevent these from depending solely on the key itself, we extend both private and public keys first with an extra 256 bits of entropy. This extension, called the chain code, is identical for corresponding private and public keys, and consists of 32 bytes.
We represent an extended private key as (k, c), with k the normal private key, and c the chain code. An extended public key is represented as (K, c), with K = point(k) and c the chain code.
Each extended key has 231 normal child keys, and 231 hardened child keys. Each of these child keys has an index. The normal child keys use indices 0 through 231-1. The hardened child keys use indices 231 through 232-1. To ease notation for hardened key indices, a number iH represents i+231.
在接下來的內容中,我們將定義一個函數,該函數從父鍵派生許多子鍵。為了防止它們完全依賴於密鑰本身,我們首先使用額外的256位熵來擴展私鑰和公鑰。這個擴展稱為chain code由32個字節組成,對於相應的公私鑰,這個chain code是相同的。(鏈碼chain code是用來給這個過程引入確定性隨機數據的,使得索引不能充分衍生其他的子密鑰。因此,有了子密鑰並不能讓它發現自己的姊妹密鑰,除非你已經有了鏈碼。)
我們將擴展私鑰表示為(k, c),普通私鑰為k,chain code為c。擴展公鑰表示為(K, c),其中K = point(K), c為chain code。
每個擴展密鑰有231個普通子keys和231個硬子keys。每個子keys都有一個索引。普通的子keys使用索引0到231-1。硬子keys使用索引231到231-1。為了簡化hardened索引的符號,一個數字iH表示i+231。
⚠️什么是hardened:(來自https://blog.csdn.net/m0_37847176/article/details/82011876 )
從擴展公鑰衍生一個分支公鑰的能力是很重要的,但牽扯一些風險。訪問擴展公鑰並不能得到訪問子私鑰的途徑。但是,因為擴展公鑰包含有鏈碼,如果某一個子私鑰被知道或者被泄漏的話,鏈碼就可以被用來衍生所有的其他子私鑰。簡單地說就是泄露的私鑰加上一個母鏈碼就可以暴露所有的子密鑰。更糟糕的是,子私鑰與母鏈碼可以用來推斷母私鑰。
為了應對這種風險,HD 錢包使用一種叫做硬化衍生(hardened derivation)的替代 衍生函數。這就“打破”了母公鑰以及子鏈碼之間的關系。這個硬化衍生函數使用了母私鑰去推導子鏈碼,而不是母公鑰。這就在母/子順序中創造了一道“防火 牆”——有鏈碼但並不能夠用來推算子私鑰或者姊妹私鑰。強化衍生函數看起來幾乎與一般的衍生的子私鑰相同,不同的是母私鑰被用來輸入散列函數中而不是母公鑰。
簡單地來說,如果你想要利用擴展公鑰的便捷來衍生公鑰的分支而不將你自己暴露在泄露擴展鏈碼的風險下, 你應該使用hardened母私鑰來衍生子公鑰,而不是從一般的母私鑰來衍生。最好的方式是,為了避免了推導出主密鑰,主密鑰所衍生的第一層級的子密鑰最好使用hardened衍生。其索引下標帶H,即iH。
Child key derivation (CKD) functions
Given a parent extended key and an index i, it is possible to compute the corresponding child extended key. The algorithm to do so depends on whether the child is a hardened key or not (or, equivalently, whether i ≥ 231), and whether we're talking about private or public keys.
給定父擴展key和索引i,可以計算相應的子擴展key。這個算法,取決於child是否硬key(即是否 索引i≥231),以及我們討論的是公鑰還是私鑰。
Private parent key → private child key 父私鑰->子私鑰
The function CKDpriv((kpar, cpar), i) → (ki, ci) computes a child extended private key from the parent extended private key從父擴展私鑰計算子擴展私鑰:
- Check whether i ≥ 231 (whether the child is a hardened key).首先檢查是否索引i ≥ 231(即是不是hardened key)
- If so (hardened child): let I = HMAC-SHA512(Key = cpar, Data = 0x00 || ser256(kpar) || ser32(i)). (Note: The 0x00 pads the private key to make it 33 bytes long.)如果是,則I = HMAC-SHA512(Key = cpar, Data = 0x00 || ser256(kpar) || ser32(i))(0x00填充私鑰,使其長度為33字節)
- If not (normal child): let I = HMAC-SHA512(Key = cpar, Data = serP(point(kpar)) || ser32(i)).如果不是則..
- Split I into two 32-byte sequences, IL and IR. 然后將I分成左右兩個32字節的序列
- The returned child key ki is parse256(IL) + kpar (mod n). 返回的子key ki為parse256(IL) + kpar (mod n)
- The returned chain code ci is IR. 返回的chain code ci為右序列IR
- In case parse256(IL) ≥ n or ki = 0, the resulting key is invalid, and one should proceed with the next value for i. (Note: this has probability lower than 1 in 2127.) 要防止parse256(IL)≥n或Ki = 0的情況,因為由此產生的key是無效的,應該計算下一個索引i。(注意:這個概率低於1 /2127)。
The HMAC-SHA512 function is specified in RFC 4231.
Public parent key → public child key 父公鑰 → 子公鑰
The function CKDpub((Kpar, cpar), i) → (Ki, ci) computes a child extended public key from the parent extended public key. It is only defined for non-hardened child keys.從父擴展公鑰計算子擴展公鑰。它只定義為非hardened child
- Check whether i ≥ 231 (whether the child is a hardened key).檢查是否為hardened child
- If so (hardened child): return failure 是則失敗
- If not (normal child): let I = HMAC-SHA512(Key = cpar, Data = serP(Kpar) || ser32(i)). 不是則..
- Split I into two 32-byte sequences, IL and IR. 然后將I分成左右兩個32字節的序列
- The returned child key Ki is point(parse256(IL)) + Kpar. 返回的子key ki point(parse256(IL)) + Kpar
- The returned chain code ci is IR. 返回的chain code ci為右序列IR
- In case parse256(IL) ≥ n or Ki is the point at infinity, the resulting key is invalid, and one should proceed with the next value for i.要防止parse256(IL)≥n或Ki點在無窮遠處的情況,由此產生的key是無效的,應該繼續計算下一個索引i。
Private parent key → public child key 父私鑰 → 子公鑰
The function N((k, c)) → (K, c) computes the extended public key corresponding to an extended private key (the "neutered" version, as it removes the ability to sign transactions).計算與擴展私鑰對應的擴展公鑰(“neutered”版本,因為它刪除了簽署交易的能力)。
- The returned key K is point(k). 返回的密鑰K是point(k)
- The returned chain code c is just the passed chain code.返回的鏈碼c只是傳遞的鏈碼
To compute the public child key of a parent private key:要計算父私鑰的公用子密鑰
- N(CKDpriv((kpar, cpar), i)) (works always).
- CKDpub(N(kpar, cpar), i) (works only for non-hardened child keys).僅適用於非硬化子密鑰
The fact that they are equivalent is what makes non-hardened keys useful (one can derive child public keys of a given parent key without knowing any private key), and also what distinguishes them from hardened keys. The reason for not always using non-hardened keys (which are more useful) is security; see further for more information.
上面兩個式子是等價的這一事實使non-hardened keys變得有用(人們可以在不知道任何私鑰的情況下派生出給定父鍵的子公鑰),這也使它們區別於hardened keys。不總是使用non-hardened keys(這個十分有用的keys)的原因是因為安全;有關更多信息,請參閱下文。
Public parent key → private child key 父公鑰 → 子私鑰
This is not possible.
The key tree
The next step is cascading several CKD constructions to build a tree. We start with one root, the master extended key m. By evaluating CKDpriv(m,i) for several values of i, we get a number of level-1 derived nodes. As each of these is again an extended key, CKDpriv can be applied to those as well.
下一步是級聯幾個CKD結構來構建樹。我們從一個根開始,主擴展key m。通過對幾個 i 值求 CKDpriv(m,i),我們得到了許多一級派生節點
To shorten notation, we will write CKDpriv(CKDpriv(CKDpriv(m,3H),2),5) as m/3H/2/5. Equivalently for public keys, we write CKDpub(CKDpub(CKDpub(M,3),2),5) as M/3/2/5. This results in the following identities:
為了縮短符號,我們將寫入CKDpriv(CKDpriv(m,3H),2),5)作為m / 3H / 2/5。我們寫入CKDpub(CKDpub(M,3),2),5)作為M / 3/2/5,其等同於公鑰。
- N(m/a/b/c) = N(m/a/b)/c = N(m/a)/b/c = N(m)/a/b/c = M/a/b/c.
- N(m/aH/b/c) = N(m/aH/b)/c = N(m/aH)/b/c.
However, N(m/aH) cannot be rewritten as N(m)/aH, as the latter is not possible.然而,N(m/aH)不能被重寫為N(m)/aH,因為后者是不可能的。
Each leaf node in the tree corresponds to an actual key, while the internal nodes correspond to the collections of keys that descend from them. The chain codes of the leaf nodes are ignored, and only their embedded private or public key is relevant. Because of this construction, knowing an extended private key allows reconstruction of all descendant private keys and public keys, and knowing an extended public keys allows reconstruction of all descendant non-hardened public keys.
樹中的每個葉節點對應於一個實際的鍵,而內部節點對應於從它們派生的鍵集合。忽略葉節點的chain codes,只有它們的嵌入私有或公共密鑰是相關的。由於這種結構,知道擴展的私鑰可以重建所有后代的私鑰和公鑰,而知道擴展的公鑰可以重建所有后代的non-hardened公鑰。
Key identifiers 密鑰標識符
Extended keys can be identified by the Hash160 (RIPEMD160 after SHA256) of the serialized ECDSA public key K, ignoring the chain code. This corresponds exactly to the data used in traditional Bitcoin addresses. It is not advised to represent this data in base58 format though, as it may be interpreted as an address that way (and wallet software is not required to accept payment to the chain key itself).
The first 32 bits of the identifier are called the key fingerprint.
擴展密鑰可以由序列化的ECDSA公鑰K的Hash160 (SHA256之后的RIPEMD160)標識,而不考慮chain code。這與傳統比特幣地址使用的數據完全一致。不過,不建議以base58格式表示該數據,因為它可能被轉成這樣格式的地址(錢包軟件不需要接受支付給chain key本身的付款)
標識符的前32位稱為密鑰指紋。
Serialization format序列化格式
Extended public and private keys are serialized as follows就是怎么講擴展公私鑰序列化,下面為每個字節所對應的內容:
- 4 byte: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private; testnet: 0x043587CF public, 0x04358394 private)版本字節
- 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 derived keys, .... 深度:主節點為0x00,級別1派生密鑰為0x01
- 4 bytes: the fingerprint of the parent's key (0x00000000 if master key) 父密鑰的指紋(如果主密鑰為0x00000000)
- 4 bytes: child number. This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. (0x00000000 if master key) 子數字。這是對於i在xi = xpar/i中的ser32(i),其中xi是鍵序列化。 (如果主密鑰為0x00000000)
- 32 bytes: the chain code 鏈碼
- 33 bytes: the public key or private key data (serP(K) for public keys, 0x00 || ser256(k) for private keys) 公鑰或私鑰數據
This 78 byte structure can be encoded like other Bitcoin data in Base58, by first adding 32 checksum bits (derived from the double SHA-256 checksum), and then converting to the Base58 representation. This results in a Base58-encoded string of up to 112 characters. Because of the choice of the version bytes, the Base58 representation will start with "xprv" or "xpub" on mainnet, "tprv" or "tpub" on testnet.
Note that the fingerprint of the parent only serves as a fast way to detect parent and child nodes in software, and software must be willing to deal with collisions. Internally, the full 160-bit identifier could be used.
When importing a serialized extended public key, implementations must verify whether the X coordinate in the public key data corresponds to a point on the curve. If not, the extended public key is invalid.
這個78字節結構可以像其他Base58形式的比特幣數據那樣進行編碼,首先添加32個校驗和位(源自double SHA-256校驗和),然后轉換為Base58表示。這將導致一個由多達112個字符組成的base58編碼的字符串。由於選擇了版本字節,Base58表示將在mainnet上以“xprv”或“xpub”開始,在testnet上以“tprv”或“tpub”開始。
注意,父節點的指紋只能作為檢測軟件中父節點和子節點的一種快速方法,軟件必須願意處理沖突。在內部,可以使用完整的160位標識符。
在導入序列化的擴展公鑰時,該實現過程必須驗證公鑰數據中的X坐標是否對應於曲線上的一點。如果沒有,擴展的公鑰無效。
⚠️extend key的作用:
在產生 child 的過程中最重要的兩個參數是 parent private key(再生成parent public key) 和 parent chain code 了。可以在生成child時同時得到該child的extend key,這樣下次還想得到一層層同樣索引的child時,不用從頭一直索引下來得到,而是可以直接使用extend key這個長長的字符串來得到child。
Master key generation主鍵生成(seed->masterkey,seed一般使用BIP39標准)
The total number of possible extended keypairs is almost 2512, but the produced keys are only 256 bits long, and offer about half of that in terms of security. Therefore, master keys are not generated directly, but instead from a potentially short seed value.
可能擴展的密鑰對的總數接近2512個,但是產生的密鑰只有256位長,並且將一半的數量用於安全。因此,主鍵不是直接生成的,而是從潛在的短seed value生成的。
- Generate a seed byte sequence S of a chosen length (between 128 and 512 bits; 256 bits is advised) from a (P)RNG.從(P)RNG中生成一個長度(128至512位之間,建議256位)的種子字節序列S;。
- Calculate I = HMAC-SHA512(Key = "Bitcoin seed", Data = S) 計算I
- Split I into two 32-byte sequences, IL and IR. 然后將I分成左右兩個32字節的序列
- Use parse256(IL) as master secret key, and IR as master chain code. 使用parse256(IL)作為主密鑰,IR作為chain code
In case IL is 0 or ≥n, the master key is invalid.如果IL is 0 or ≥n,主鍵無效
該圖來自:https://blog.csdn.net/m0_37847176/article/details/82011876
主私鑰(m) 可以通過橢圓曲線生成相應的主公鑰(M)。 鏈代碼用於從主密鑰中創造子密鑰的函數中引入熵,即擴展密鑰處。
Specification: Wallet structure
The previous sections specified key trees and their nodes. The next step is imposing a wallet structure on this tree. The layout defined in this section is a default only, though clients are encouraged to mimic it for compatibility, even if not all features are supported.
前面的部分指定了關鍵樹及其節點。下一步是在這棵樹上安裝一個wallet結構。本節中定義的布局僅為默認布局,但鼓勵客戶為了兼容性而模仿它,即使它不支持所有特性。
The default wallet layout默認wallet布局
An HDW is organized as several 'accounts'. Accounts are numbered, the default account ("") being number 0. Clients are not required to support more than one account - if not, they only use the default account.
HDW被組織為幾個“帳戶”。帳戶即數字編號,默認帳戶("")編號為0。客戶不需要支持多個帳戶——如果不支持,他們只使用默認帳戶。
Each account is composed of two keypair chains: an internal and an external one. The external keychain is used to generate new public addresses, while the internal keychain is used for all other operations (change addresses, generation addresses, ..., anything that doesn't need to be communicated). Clients that do not support separate keychains for these should use the external one for everything.
每個帳戶由兩個密鑰對鏈組成:一個內部密鑰對鏈和一個外部密鑰對鏈。外部密鑰鏈用於生成新的公共地址,而內部密鑰鏈用於所有其他操作(更改地址、生成地址、…,任何不需要溝通的事情)。不支持這種分開的密鑰鏈的客戶端應該將外部密鑰鏈用於所有事情。
- m/iH/0/k corresponds to the k'th keypair of the external chain of account number i of the HDW derived from master m.對應於主鍵m派生的HDW的第i個賬號的外部鏈的第k個密鑰對
- m/iH/1/k corresponds to the k'th keypair of the internal chain of account number i of the HDW derived from master m.對應於主鍵m派生的HDW的第i個賬號的內部鏈的第k個密鑰對
Use cases
Full wallet sharing: m主私鑰
In cases where two systems need to access a single shared wallet, and both need to be able to perform spendings, one needs to share the master private extended key. Nodes can keep a pool of N look-ahead keys cached for external chains, to watch for incoming payments. The look-ahead for internal chains can be very small, as no gaps are to be expected here. An extra look-ahead could be active for the first unused account's chains - triggering the creation of a new account when used. Note that the name of the account will still need to be entered manually and cannot be synchronized via the block chain.
如果兩個系統需要訪問一個共享的錢包,並且兩個系統都需要能夠執行開銷,那么需要共享主私有擴展密鑰。節點可以為外部鏈緩存N個向前查找鍵,以監視傳入的付款。內部鏈的向前查找的可能非常小,因為在這里沒有缺口。對於第一個未使用的帳戶鏈,一個額外的向前查找功能可能是活躍的——即在使用時觸發一個新帳戶的創建。注意,帳戶的名稱仍然需要手動輸入,不能通過塊鏈進行同步
Audits: N(m/*)
In case an auditor needs full access to the list of incoming and outgoing payments, one can share all account public extended keys. This will allow the auditor to see all transactions from and to the wallet, in all accounts, but not a single secret key.
如果審計人員需要能夠完全地訪問收支付款清單,可以共享所有帳戶的公共擴展密鑰。這將允許審計人員查看所有賬戶中來自錢包和到錢包的所有交易,但不查看任何一個秘密密鑰。
Per-office balances: m/iH
When a business has several independent offices, they can all use wallets derived from a single master. This will allow the headquarters to maintain a super-wallet that sees all incoming and outgoing transactions of all offices, and even permit moving money between the offices.
當一個公司有幾個獨立的辦公室時,他們都可以使用從一個master那里得到的錢包。這將使總部擁有一個超級錢包,可以看到所有辦公室的所有進出交易,甚至允許在辦公室之間轉移資金。
Recurrent business-to-business transactions: N(m/iH/0)周期性b2b交易
In case two business partners often transfer money, one can use the extended public key for the external chain of a specific account (M/i h/0) as a sort of "super address", allowing frequent transactions that cannot (easily) be associated, but without needing to request a new address for each payment. Such a mechanism could also be used by mining pool operators as variable payout address.
如果兩個業務伙伴經常轉賬,一個可以將特定帳戶(M/i h/0)的外部鏈的擴展公鑰用作一種“超級地址”,允許頻繁的交易,這些交易不能(容易地)關聯,但無需為每次支付請求新的地址。這種機制也可以被挖掘池運營商用作可變支付地址。
Unsecure money receiver: N(m/iH/0)
When an unsecure webserver is used to run an e-commerce site, it needs to know public addresses that are used to receive payments. The webserver only needs to know the public extended key of the external chain of a single account. This means someone illegally obtaining access to the webserver can at most see all incoming payments but will not be able to steal the money, will not (trivially) be able to distinguish outgoing transactions, nor be able to see payments received by other webservers if there are several.
當不安全的web服務器用於運行電子商務網站時,它需要知道用於接收付款的公共地址。web服務器只需要知道單個帳戶外部鏈的公共擴展密鑰。這意味着,非法訪問webserver的人最多只能看到所有收到的付款,但卻無法竊取資金,無法(簡單地)區分出傳出的交易,也無法看到其他web服務器收到的付款(如果有幾個的話)。
Compatibility
To comply with this standard, a client must at least be able to import an extended public or private key, to give access to its direct descendants as wallet keys. The wallet structure (master/account/chain/subchain) presented in the second part of the specification is advisory only, but is suggested as a minimal structure for easy compatibility - even when no separate accounts or distinction between internal and external chains is made. However, implementations may deviate from it for specific needs; more complex applications may call for a more complex tree structure.
為了符合這個標准,客戶端必須至少能夠導入擴展的公共或私有密鑰,以便能夠訪問其直接后代作為錢包密鑰。在規范的第二部分中提出的錢包結構(主/帳戶/鏈/子鏈)僅僅是建議性的,但是建議作為一種最小的結構,以方便兼容性—即使沒有單獨的帳戶或內部和外部鏈之間的區別。但是,真正的實現可能因某些特定需要而偏離該結構;更復雜的應用程序可能需要更復雜的樹結構。
Security
In addition to the expectations from the EC public-key cryptography itself除了來自橢圓曲線公開密鑰加密本身的預期:
- Given a public key K, an attacker cannot find the corresponding private key more efficiently than by solving the EC discrete logarithm problem (assumed to require 2128 group operations).給定一個公鑰K,攻擊者無法比通過解決EC離散對數問題(假設需要2128
組操作)更有效地找到對應的私鑰
the intended security properties of this standard are本標准的預期安全屬性為:
- Given a child extended private key (ki,ci) and the integer i, an attacker cannot find the parent private key kpar more efficiently than a 2256 brute force of HMAC-SHA512.給定一個子擴展私鑰(ki,ci)和整數i,攻擊者無法找到比使用2256的蠻力HMAC-SHA512方法更有效的方法去找到父私鑰kpar
- Given any number (2 ≤ N ≤ 232-1) of (index, extended private key) tuples (ij,(kij,cij)), with distinct ij's, determining whether they are derived from a common parent extended private key (i.e., whether there exists a (kpar,cpar) such that for each j in (0..N-1) CKDpriv((kpar,cpar),ij)=(kij,cij)), cannot be done more efficiently than a 2256 brute force of HMAC-SHA512. 給定任意數量(2≤N≤232 - 1)(指數,擴展私鑰)的元組(ij,(kij,cij)),與不同的ij,攻擊者無法找到比使用2256的蠻力的HMAC-SHA512方法更有效的方法去確定他們是否來自一個共同的父私鑰(即對於來自(0..N-1) CKDpriv((kpar,cpar),ij)=(kij,cij)中的每個j是否都存在一個(kpar,cpar)來滿足該式子)。
Note however that the following properties does not exist但是請注意,以下屬性不存在:
- Given a parent extended public key (Kpar,cpar) and a child public key (Ki), it is hard to find i.給定一個父擴展公鑰(Kpar,cpar)和一個子公鑰(Ki),很難找到i
- Given a parent extended public key (Kpar,cpar) and a non-hardened child private key (ki), it is hard to find kpar.給定父擴展公鑰(Kpar,cpar)和non-hardened子私鑰(ki),很難找到kpar。
Implications
Private and public keys must be kept safe as usual. Leaking a private key means access to coins - leaking a public key can mean loss of privacy.
Somewhat more care must be taken regarding extended keys, as these correspond to an entire (sub)tree of keys.
One weakness that may not be immediately obvious, is that knowledge of a parent extended public key plus any non-hardened private key descending from it is equivalent to knowing the parent extended private key (and thus every private and public key descending from it). This means that extended public keys must be treated more carefully than regular public keys. It is also the reason for the existence of hardened keys, and why they are used for the account level in the tree. This way, a leak of account-specific (or below) private key never risks compromising the master or other accounts.
私有和公鑰必須像往常一樣保持安全。泄漏私鑰意味着對硬幣的訪問——泄漏公鑰可能意味着隱私的喪失。
對於擴展鍵,需要多加注意,因為它們對應於鍵的整個(子)樹。
有一個缺點可能不是很明顯,即父擴展公鑰的值加上從它生成的任何non-hardened私鑰,就相當於知道父擴展私鑰(因此每個私鑰和公鑰都是從它生成的)。這意味着擴展公鑰必須比常規公鑰更小心地處理。這也是hardened鍵存在的原因(之前說過為什么沒有都使用non-hardened鍵),也是為什么它們用於樹中的帳戶級別。通過這種方式,特定賬戶(或以下)私鑰的泄漏永遠不會危及主賬戶或其他賬戶。
Test Vectors測試向量
Test vector 1
Seed (hex): 000102030405060708090a0b0c0d0e0f
- Chain m 主鍵
- ext pub: xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8
- ext prv: xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi
- Chain m/0H 第一個賬戶account
- ext pub: xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw
- ext prv: xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7
- Chain m/0H/1 第一個賬戶的內部chain
- ext pub: xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ
- ext prv: xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
- Chain m/0H/1/2H 第一個賬戶的內部chain的第三個subchain
- ext pub: xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5
- ext prv: xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM
- Chain m/0H/1/2H/2 第一個賬戶的內部chain的第三個subchain的第三個address
- ext pub: xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV
- ext prv: xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334
- Chain m/0H/1/2H/2/1000000000
- ext pub: xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy
- ext prv: xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76
go運行時遇見問題:
1.
userdeMBP:src user$ go get golang.org/x/crypto/ripemd160 package golang.org/x/crypto/ripemd160: unrecognized import path "golang.org/x/crypto/ripemd160" (https fetch: Get https://golang.org/x/crypto/ripemd160?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)
由於國內網絡原因,因此訪問https://golang.org/網站會被限制。所以在go get下載其他第三方包的時候,如果這個第三方包又引用了https://golang.org/x/下的包,通常會下載失敗,就會報這個錯誤
參考:https://blog.csdn.net/weixin_42280360/article/details/80649038
2.
userdeMBP:src user$ go build hd-wallet.go # command-line-arguments ./hd-wallet.go:6:1: syntax error: non-declaration statement outside function body
要將運行內容寫入func main(){}
3.
userdeMBP:src user$ go build hd-wallet.go # command-line-arguments ./hd-wallet.go:7:8: err declared and not used ./hd-wallet.go:16:2: childprv declared and not used ./hd-wallet.go:20:2: address declared and not used ./hd-wallet.go:25:2: childaddress declared and not used
因為代碼中有聲明並賦值了err該變量,但是並沒有使用,所以使用_來代替它
其他的使用fmt.Println(childaddress)來使用他們
實例:
package main import( "github.com/WeMeetAgain/go-hdwallet" "fmt" ) func main(){ // Generate a random 256 bit seed // seed, _ := hdwallet.GenSeed(256) //fmt.Println(seed) // Create a master private key var str string = "0x000102030405060708090a0b0c0d0e0f" var seed []byte = []byte(str) masterprv := hdwallet.MasterKey(seed) fmt.Println(masterprv) //xprv9s21ZrQH143K3sGikPVJnaJkPsjhuxHxrXVTVB256AnXAFbKstG6pi6nhxZg4VrXCGo9Zrn98bYe6brrmtM5sR1YU8ADbfoHAjVv6R4QXQo // Convert a private key to public key masterpub := masterprv.Pub() fmt.Println(masterpub) //xpub661MyMwAqRbcGMMBrR2K9iFUwuaCKR1pDkR4HZRgeWKW33vURRaMNWRGZFyuKD8NRe17vAsWBwfRSpoghXqXRz8NmkN6bdgdhUbuJEcqSJE // Generate new child key based on private or public key childprv, _ := masterprv.Child(0) childpub, _ := masterpub.Child(0) fmt.Println(childprv) //xprv9uXEX9538uj8iiLcTYzvMMxRv4LCNWpZDNpEGJJZd15CJHoCoYSY7LFhqo5xM4n8Bo9qpo7hoQxWva6rs6CL7nCyYj9boVLSiUPXAeYpZ4R fmt.Println(childpub) //xpub68WavebvyHHRwCR5ZaXviVuAU6AgmyYQabjq4giBBLcBB68MM5knf8aBh584hYmB18yYzkvmrH2pnXmUYdjgborGr3DrgH6zpkcDetpzuNB // Create bitcoin address from public key address := childpub.Address() fmt.Println(address) //17wNBYV1482MeGQorJF7RJkefxbqf7My5w // Convenience string -> string Child and ToAddress functions,使用extend key直接得到上面的child的child walletstring := childpub.String() // String returns the base58-encoded string form of the wallet.以上面的child作為wallet childstring, _ := hdwallet.StringChild(walletstring,0) //return extended key,然后一次得到它的child(0)的extended key childaddress, _ := hdwallet.StringAddress(childstring) //使用extended key直接得到一個child fmt.Println(walletstring) //xpub68WavebvyHHRwCR5ZaXviVuAU6AgmyYQabjq4giBBLcBB68MM5knf8aBh584hYmB18yYzkvmrH2pnXmUYdjgborGr3DrgH6zpkcDetpzuNB fmt.Println(childstring) //xpub6BaCw5HC1yM4H3aC4L4SaZsKVMzXxbfVYiCsoVXz91eFuRnyn6CxJmpNCFqxzFtjSsY9GsdwbNTQZK2mqnsPndwJrtKznLnjSGTqMEAwTQE fmt.Println(childaddress) //1HyLGa9BLV843eQJKTxQb38HZnR9M9WUMx //這里是使用正常的方法,可以看見結果是相同的 chiChildpub,_ := childpub.Child(0) chiAddress := chiChildpub.Address() fmt.Println(chiChildpub) //xpub6BaCw5HC1yM4H3aC4L4SaZsKVMzXxbfVYiCsoVXz91eFuRnyn6CxJmpNCFqxzFtjSsY9GsdwbNTQZK2mqnsPndwJrtKznLnjSGTqMEAwTQE fmt.Println(chiAddress) }