什么是 HD 钱包
HD 钱包是目前常用的确定性钱包 ,说到 HD 钱包,大家可能第一反应会想到硬件钱包 (Hardware wallet),其实这里的 HD 是 Hierarchical Deterministic(分层确定性)的缩写。所谓分层,就是一个大公司可以为每个子部门分别生成不同的私钥,子部门还可以再管理子子部门的私钥,每个部门可以看到所有子部门里的币,也可以花这里面的币。也可以只给会计人员某个层级的公钥,让他可以看见这个部门及子部门的收支记录,但不能花里面的钱,使得财务管理更方便了。
分层确定性的概念早在比特币改进提案 BIP32提出。根据比特币核心开发者 Gregory Maxwell 的原始描述和讨论,Pieter Wuille 在2012 年 02月 11日整理完善提交 BIP32 。直到 2016年 6月 15 日 才被合并到进入 Bitcoin Core,目前几乎所有的钱包服务供应商都整合了该协议。BIP 32是 HD 钱包的核心提案,通过种子来生成主私钥,然后派生海量的子私钥和地址,但是种子是一串很长的随机数,不利于记录,所以我们用算法将种子转化为一串助记词 (Mnemonic),方便保存记录,这就是 BIP 39,它扩展了 HD 钱包种子的生成算法。BIP43 对 BIP32 树结构增加了子索引标识 purpose 的扩展 m/purpose'/ *
。 BIP44是在 BIP43 和 BIP32 的基础上增加多币种,通过 HD 钱包派生多个地址,可以同时管理主网和测试网的比特币,BIP44 提出了 5 层的路径建议,如下:m/purpse’/coin_type’/account’/change/address_index
,
BIP44 的规则使得 HD 钱包非常强大,用户只需要保存一个种子,就能控制所有币种,所有账户的钱包。
比特币 HD 钱包是如何生成的?
1、生成一个助记词(参见 BIP39)
2、该助记词使用 PBKDF2 转化为种子(参见 BIP39)
3、种子用于使用 HMAC-SHA512 生成根私钥(参见BIP32)
4、从该根私钥,导出子私钥(参见BIP32),其中节点布局由BIP44设置
10、DeterministicSeed.java:种子的产生
@Nullable private final byte[] seed;
@Nullable private final List<String> mnemonicCode; // only one of mnemonicCode/encryptedMnemonicCode will be set
@Nullable private final EncryptedData encryptedMnemonicCode;
@Nullable private EncryptedData encryptedSeed;
我们可以看到对应种子seed,助记词 mnemonicCode
在DeterministicSeed有如何通过助记词生成种子,通过BIP39协议
/**
* Constructs a seed from a BIP 39 mnemonic code. See {@link MnemonicCode} for more
* details on this scheme.
* @param entropy entropy bits, length must be divisible by 32
* @param passphrase A user supplied passphrase, or an empty string if there is no passphrase
* @param creationTimeSeconds When the seed was originally created, UNIX time.
*/
public DeterministicSeed(byte[] entropy, String passphrase, long creationTimeSeconds) {
this.mnemonicCode = MnemonicCode.INSTANCE.toMnemonic(entropy);
............
this.seed = MnemonicCode.toSeed(mnemonicCode, passphrase);
我们可以看到, passphrase 是用户输入口令产生了mnemonicCode、seed。
DeterministicSeed 还提供了对seed的加密encrypt、解密decrypt,为了安全。
BIP32
比较复杂,具体产生子公钥和子密钥见 https://github.com/bitcoin/bips/blob/master/bip-0032/derivation.png?raw=true
重点先掌握基本钱包分层结构,比特币Wallet基于BIP32基础
大体钱包分层架构
11、DeterministicKeyChain.java
默认采用非确定钱包
A deterministic key chain is a {@link KeyChain} that uses theBIP 32 standard, as implemented by{@link DeterministicHierarchy}, to derive all the keys in the keychain from a master seed.不过要注意,如果交易比较频繁,私钥可能会用光,然后再产生一批私钥,所以每次完成 100 个交易后,你必须备份新的 wallet.dat 文件,否则可能会丢失资产
The default lookahead zone is 100 keys, meaning if the user hands out more than 100 addresses and receives payment on them before the chain is next scanned, some transactions might be missed.
Key chains 产生的Keys具体干什么?结合到上图,看看钱包布局
The default wallet layout
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.
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.
<li>m/i<sub>H</sub>/0/k corresponds to the k'th keypair of the external chain of account number i of the HDW derived from master m.</li>
<li>m/i<sub>H</sub>/1/k corresponds to the k'th keypair of the internal chain of account number i of the HDW derived from master m.</li>
看看具体Keys 代码怎么产生的
/* Returns freshly derived key/s that have not been returned by this method before. /
@Override
public List<DeterministicKey> getKeys(KeyPurpose purpose, int numberOfKeys) {
List<DeterministicKey> <span class="s1">keys</span> = <span class="s2">new</span> ArrayList<>(<span class="s1">numberOfKeys</span>);
for (int i = 0; i < numberOfKeys; i++) {
ImmutableList<ChildNumber> path = HDUtils.append(parentKey.getPath(), new ChildNumber(index - numberOfKeys + i, false));
DeterministicKey k = hierarchy.get(path, false, false);
checkForBitFlip(k);
keys.add(k);
}
12、DeterministicHierarchy.java
上图 hierarchy是一个DeterministicHierarchy对象,它的描述
A DeterministicHierarchy calculates and keeps a whole tree (hierarchy) of keys originating from a single
root key. This implements part of the BIP 32 specification
我们直观看个例子:
<li><a href="https://link.juejin.im?target=https%3A%2F%2Fgithub.com%2Fbitcoin%2Fbips%2Fblob%2Fmaster%2Fbip-0044.mediawiki" target="_blank" rel="nofollow noopener noreferrer">BIP44</a>:基于 BIP32 的系统,赋予树状结构中的各层特殊的意义。让同一个 seed 可以支援多币种、多帐户等。各层定义如下:</li>
m / purpose' / coin_type' / account' / change / address_index
//purporse': 固定值44', 代表是BIP44
//coin_type': 这个代表的是币种, 可以兼容很多种币, 比如BTC是0', ETH是60'
//btc一般是 m/44'/0'/0'/0
//eth一般是 m/44'/60'/0'/0
我们通过工具自己生成BIP32下一组Key
根据BIP39协议,首先我们自己输入一个助记词
我们选择HD Wallet,开始构造Tree,生成对应Extended Private/Public Key.
最后生成我们想要最后节点,比特币的Address,对应有它的Private/Public Key,用来做BlockChain上交易签名,验证。
13、KeyChainGroup.java
A KeyChainGroup: is used by the {@link Wallet} and manages: a {@link BasicKeyChain} object (which will normally be empty), and zero or more {@link DeterministicKeyChain}s.