助记词的由来,从HD钱包的创建方式可知,要创建一个HD钱包,我们必须首先有一个确定的512bit(64字节)的随机数种子。
从HD钱包的创建方式可知,要创建一个HD钱包,我们必须首先有一个确定的512bit(64字节)的随机数种子。
如果用电脑生成一个64字节的随机数作为种子当然是可以的,但是恐怕谁也记不住。
如果自己想一个句子,例如bitcoin is awesome
,然后计算SHA-512获得这个64字节的种子,虽然是可行的,但是其安全性取决于自己想的句子到底有多随机。像bitcoin is awesome
本质上就是3个英文单词构成的随机数,长度太短,所以安全性非常差。
为了解决初始化种子的易用性问题,BIP-39规范提出了一种通过助记词来推算种子的算法。
以英文单词为例,首先,挑选2048个常用的英文单词,构造一个数组:
const words = ['abandon', 'ability', 'able', ..., 'zoo'];
理想的单词表具有以下特点:
然后,生成128~256位随机数,注意随机数的总位数必须是32的倍数。例如,生成的256位随机数以16进制表示为:
179e5af5ef66e5da5049cd3de0258c5339a722094e0fdbbbe0e96f148ae80924
在随机数末尾加上校验码,校验码取SHA-256的前若干位,并使得总位数凑成11的倍数。上述随机数校验码的二进制表示为00010000
。
将随机数+校验码按每11 bit一组,得到范围是0~2047的24个整数,把这24个整数作为索引,就得到了最多24个助记词,例如:
bleak version runway tell hour unfold donkey defy digital abuse glide please much imit cement sea sweet tenant demise taste emerge inject cause low
由于在生成助记词的过程中引入了校验码,所以,助记词如果弄错了,软件可以提示用户输入的助记词可能不对。
生成助记词的过程是计算机随机产生的,用户只要记住这些助记词,就可以根据助记词推算出HD钱包的种子。
生成助记词可以使用ethers这个JavaScript库:
const { ethers } = require("ethers");
let mnKey1=ethers.utils.randomBytes(32);
let mnemonic = ethers.utils.entropyToMnemonic(mnKey1);
console.log(mnemonic);
运行上述代码,每次都会得到随机生成的不同的助记词。
node
//连接服务器8545端口获取以太坊请求 var Web3=require('web3') var web3=new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8545"))
//创建账户,返回公钥,并且可以在keystore目录下,找到该账户的keystore文件 web3.eth.personal.newAccount('password').then(console.log)
0xCca85C3b3A51a2c4375cE11353723f0b87FDe0Ac
//使用该账户的keystore文件解密账号,首先读取keystore文件 keystore1 = fs.readFileSync('../blockchain/keystore/UTC--2021-04-04T07-28-18.289403810Z--cca85c3b3a51a2c4375ce11353723f0b87fde0ac').toString()
'{"address":"cca85c3b3a51a2c4375ce11353723f0b87fde0ac","crypto":{"cipher":"aes-128-ctr","ciphertext":"04624357707666733d17a02aed5bc7d13f00306d2fdc3c9650ed66848e5d66d7","cipherparams":{"iv":"0d7f4c79d897b91acc4459c0013982d3"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"6475f2cf0cf7cb8708c90c8d6b80bcc47d45fec98d3143a6917edf7dde5d13f2"},"mac":"ac5b890d7460fdf6de696b09efb54ef472d8fec351faf485c42597f9895c702e"},"id":"7d8abc37-5a0d-4508-ae1c-6ed2370f6e9e","version":3}'
//调用解密方法,返回了解密后的账户对象,其中包含了该账户的私钥 web3.eth.accounts.decrypt(keystore1, 'password')
{ address: '0xCca85C3b3A51a2c4375cE11353723f0b87FDe0Ac', privateKey: '0x0516d7a0fb437b25c2a3d1d2bd1c8f381a64d0ee94be5ebbb913492e4b07886d', signTransaction: [Function: signTransaction], sign: [Function: sign], encrypt: [Function: encrypt] }
//除此之外,还可以用指定私钥来创建新的账户,注意,该方法接收的私钥不能包含0x
web3.eth.personal.importRawKey('0516d7a0fb437b25c2a3d1d2bd1c8f381a64d0ee94be5ebbb913492e4b07886d','password').then(console.log)
//除此之外,也可以将指定私钥通过算法映射成助记词,原理上与上种方法一样
const { ethers } = require("ethers");
var mnKey1=ethers.utils.randomBytes(32);
mnKey1
[ 233, 190, 140, 153, 2, 229, 73, 52, 216, 222, 183, 218, 26, 159, 209, 192, 181, 223, 46, 59, 185, 174, 137, 10, 211, 191, 56, 2, 241, 17, 42, 2 ]
var words=ethers.utils.entropyToMnemonic(mnKey1);
words
'trust virtual chaos alarm fee omit gloom street sure stay virtual lift fuel novel upon cupboard math final used hybrid congress mass pool emerge'
var mnKey2 = ethers.utils.mnemonicToEntropy(words);
mnKey2
'0xe9be8c9902e54934d8deb7da1a9fd1c0b5df2e3bb9ae890ad3bf3802f1112a02'
通过对比10进制的mnKey1和16进制的mnKey2可以发现这两者是一样的。
之后使用给定私钥创建账户的方法就行。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!