Ethereum HD Wallet(虚拟货币钱包)-BIP32、BIP39、BIP44

时间:2024-02-16 17:27:58

1.使用HD钱包的好处(链接:https://www.jianshu.com/p/53405db83c16)

备份更容易

传统钱包的问题是一个钱包可能存有一堆密钥地址,每个地址都有一些比特币。这样备份钱包的时候,需要备份所有的密钥。但如果之后生成了一个新地址,你就需要重新备份一次。事实上,每次生成新地址的时候,你都需要做一次备份。 HD钱包允许你从一个主(根)密钥创建海量的子密钥。这意味着,一旦你控制了主密钥,你就可以生成所有的子密钥,主密钥和子密钥形成树状结构。所以你就不需要频繁的备份钱包,你只需要在创建钱包的时候备份一次就可以了,因为你可以从主密钥重新创建所有的子密钥。

私钥离线存放更安全

HD钱包还带来了一些新特性,比如不需要任何私钥,就可以从一个父公钥生成所有的子公钥。具体来说,你的主私钥是以纸钱包的方式备份的,并且离线存放在一个安全的地方。你手头有主公钥,用这个公钥,你就可以生成所有的子公钥。 举个实际的例子,我们要开一个网店,接受比特币付款。你可以离线存放你的私钥,只把公钥放在公网的服务器上。你的网站可以使用这个公钥为网站上的每一个商品生成一个收款地址,或者给你的每个顾客生成一个唯一的地址,甚至为每次交易生成一个地址(如何使用,取决于你的想象)。 并且因为私钥是离线存放的,没人可以黑进你的服务器偷走比特币。

权限控制

HD钱包有个额外好处,它让你可以控制你的组织里谁可以控制哪些密钥。 和一个商业组织的组织结构类似,HD钱包也是以树形结构组织密钥的。你可以给你的组织里的每个分支部门创建密钥,把私钥交给这个分支部门,这个部门就可以花它的分支上的币,而你,因为有主私钥,所以你可以看到并花费整个树上的币。

记账

想让会计看到所有的交易,但不想让他花你的钱?没问题,你可以给他任何一级上的公钥,他就可以看到该级下的所有交易,并且不能花任何的币。

2.

参考https://cloud.tencent.com/info/78dbcfc6df58fb58b13b152ae154a3e0.html

BIP 全名是 Bitcoin Improvement Proposals,是提出 Bitcoin 的新功能或改进措施的文件。

私钥通过椭圆曲线生成公钥, 公钥通过哈希函数生成地址,这两个过程都是单向的。
实际上,数字钱包实际是一个管理私钥(生成、存储、签名)的工具,注意钱包并不保存资产,资产是在链上的。

如何创建账号

创建账号关键是生成一个私钥, 私钥是一个32个字节的数, 生成一个私钥在本质上在1到2^256之间选一个数字。
因此生成密钥的第一步也是最重要的一步,是要找到足够安全的熵源,即随机性来源,只要选取的结果是不可预测或不可重复的,那么选取数字的具体方法并不重要。
比如可以掷硬币256次,用纸和笔记录正反面并转换为0和1,随机得到的256位二进制数字可作为钱包的私钥。
从编程的角度来看,一般是通过在一个密码学安全的随机源(不建议大家自己去写一个随机数)中取出一长串随机字节,对其使用SHA256哈希算法进行运算,这样就可以方便地产生一个256位的数字。

实际过程需要比较下是否小于n-1(n = 1.158 * 10^77, 略小于2^256),我们就有了一个合适的私钥。否则,我们就用另一个随机数再重复一次。这样得到的私钥就可以根据上面的方法进一步生成公钥及地址。

 

3.bip32-协议与实现看bip32

钱包也是一个私钥的容器,按照上面的方法,我们可以生成一堆私钥(一个人也有很多账号的需求,可以更好保护隐私),而每个私钥都需要备份就特别麻烦的。
最早期的比特币钱包就是就是这样,还有一个昵称:“Just a Bunch Of Keys(一堆私钥)“

为了解决这种麻烦,就有了BIP32 提议

根据一个随机数种子通过分层确定性推导的方式得到n个私钥,这样保存的时候,只需要保存一个种子就可以,私钥可以推导出来

BIP32提案的名字是:Hierarchical Deterministic Wallets, 就是我们所说的HD钱包。


来分析下这个分层推导的过程,第一步推导主秘钥的过程:

根种子输入到HMAC-SHA512算法中就可以得到一个可用来创造主私钥(m) 和 一个主链编码( a master chain code)

这一步生成的秘钥(由私钥或公钥)及主链编码再加上一个索引号,将作为HMAC-SHA512算法的输入继续衍生出下一层的私钥及链编码,如下图:
衍生推导的方案其实有两个:

  (1)一个用父私钥推导(称为强化衍生方程)

  (2)一个用父公钥推导

同时为了区分这两种不同的衍生,在索引号也进行了区分,索引号小于2^31用于常规衍生,而2^31到2^32-1之间用于强化衍生,为了方便表示索引号i\',表示2^31+i。
因此增加索引(水平扩展及 通过子秘钥向下一层(深度扩展)可以无限生成私钥。
注意, 这个推导过程是确定(相同的输入,总是有相同的输出)也是单向的,子密钥不能推导出同层级的兄弟密钥,因为子密钥并不知道 parent chain code,也不能推出父密钥。如果没有子链码也不能推导出孙密钥。现在我们已经对分层推导有了认识。
一句话概括下BIP32就是:为了避免管理一堆私钥的麻烦提出的分层推导方案

 

(2)用父公钥推导

  需要三个参数:parent public key、parent chain code和index(要产生的是下一层的第几个child),然后就能够生成子私钥和子chain code,根据子私钥就能够得到子公钥,然后我们就能够继续使用子公钥、子chain code和index再生成下一层的key,可以不停地推导下去。

 

相应协议网址-https://github.com/bitcoin/bips

4.bip39-协议和实例看bip39

在线转换器-https://iancoleman.io/bip39/#english

 

5.bip44-协议和实例看bip44

bip32 就是没有任何限制的协议,而 bip44 就是限制用户,要求用户从第四层定义开始取值,而前三层定义用于确定协议与币种。

在线实现器-https://iancoleman.io/bip39/#english

 

6.几个互相之间的关系:

生成mnemonic > 生成seed > 生成 Extended Public Key

生成地址主要依赖Extended Public Key,加上addressIndex(0至232-1)就可以确定一个地址.

BTC使用m/44’/0’/0’/0的 Extended Public Key 生成 m/44’/0’/0’/0/*,
ETH使用m/44’/60’/0’/0的 Extended Public Key 生成 m/44’/60’/0’/0/*,
mainnet的Extended Public Key以xpub做前缀,例如:

xpub68WavebvyHHRwCR5ZaXviVuAU6AgmyYQabjq4giBBLcBB68MM5knf8aBh584hYmB18yYzkvmrH2pnXmUYdjgborGr3DrgH6zpkcDetpzuNB

扩展公钥不等同于公钥,扩展公钥主要包含了3个信息: 
1) 区块链网络(mainnet 或 testnet) 
2) 公钥 
3) chain code


实现:(参考https://www.jianshu.com/p/54a2b14dfdf2)

  • bip39:实作 BIP39,随机产生新的 mnemonic code,并可以将其转成 binary 的 seed。
  • ethereumjs-wallet:产生和管理公私钥,我使用其中的 hdkey 子套件来创建 HD Wallet。
  • ethereumjs-util:集合许多 Ethereum 需要的运算功能。
npm install bip39 ethereumjs-wallet ethereumjs-util --save

 

var bip39 = require(\'bip39\')
var hdkey = require(\'ethereumjs-wallet/hdkey\')
var util = require(\'ethereumjs-util\')

//产生 mnemonic code
var mnemonic = bip39.generateMnemonic()
console.log(mnemonic)//ship dove behave merit will live other rough island curious desk push

//将 mnemonic code 转成 binary 的 seed
var seed = bip39.mnemonicToSeed(mnemonic)
console.log(seed)
//<Buffer be 06 2a 79 97 41 32 c5 30 07 2b 11 00 b8 21 4c 56 84 fe a8 d1 28 f8 6f f2 58 4e 26 20 b6 f5 70 61 8b b9 a0 46 0a 94 5b ea d9 1e 8b c4 ee 4c 65 77 29 ... 14 more bytes>

//使用 seed 产生 HD Wallet
var hdWallet = hdkey.fromMasterSeed(seed)
console.log(hdWallet)
// EthereumHDKey {
//   _hdkey:
//    HDKey {
//      versions: { private: 76066276, public: 76067358 },
//      depth: 0,
//      index: 0,
//      _privateKey:
//       <Buffer 2f 29 d8 96 63 c4 8b 34 34 f1 6b 56 44 69 f3 26 f2 e4 7d 36 71 5c 8b 03 a9 ed 2d 5b 9a 31 27 8d>,
//      _publicKey:
//       <Buffer 03 56 04 61 7d f7 68 d3 16 13 8e cc 97 21 ff 56 73 ff dd ce 69 50 af 74 76 9b 73 41 12 ea 79 82 61>,
//      chainCode:
//       <Buffer 5c c6 6e 68 6c 81 b7 a9 11 43 62 de 7b 50 a5 b8 06 66 73 a6 6f 87 4f cd ce 76 a5 95 e2 d1 0d 3e>,
//      _fingerprint: 503483031,
//      parentFingerprint: 0,
//      _identifier:
//       <Buffer 1e 02 8a 97 8b cf 89 e5 1b 0e b4 ad 06 e2 7c 26 dc b3 9f a8> } }

//产生 Wallet 中第一个帐户的第一组 keypair,以太币
var key1 = hdWallet.derivePath("m/44\'/60\'/0\'/0/0")
console.log(key1)
// EthereumHDKey {
//   _hdkey:
//    HDKey {
//      versions: { private: 76066276, public: 76067358 },
//      depth: 5,
//      index: 0,
//      _privateKey:
//       <Buffer 97 6d ad 55 91 fa f4 69 4d 36 27 c4 ab 4a 2d b4 02 32 d0 39 4e 4f da 55 06 4f 69 12 8c 67 85 b9>,
//      _publicKey:
//       <Buffer 02 6f a7 5a 3f 3b 10 9a ce 14 4c 35 91 a3 22 6e 48 b0 25 bc ad ee d8 5e de e6 ed a8 40 92 b7 a8 1f>,
//      chainCode:
//       <Buffer b8 e1 17 60 eb 3e 4c 58 44 3f bb e4 cd 9c 6f 0d 55 ed 84 8b 60 6b 64 42 e2 3f 79 fd 33 29 0e 8b>,
//      _fingerprint: 1477067077,
//      parentFingerprint: 3604950195,
//      _identifier:
//       <Buffer 58 0a 41 45 06 d2 7e ef c8 a8 fe 33 8b ca 75 04 9f 9d e2 b5> } }




//用 keypair 中的公钥产生 address
var address1 = util.pubToAddress(key1._hdkey._publicKey, true)
console.log(address1)//<Buffer 29 f6 f9 fb d3 fe 8c dd 39 83 57 1a b6 33 8c bb 1c b4 7a e2>

//生成 checksum address 
address1 = util.toChecksumAddress(address1.toString(\'hex\'))
console.log(address1)//0x29F6F9fbd3Fe8cDd3983571AB6338CBB1CB47ae2