助记词概念及以太坊实现

助记词的由来,从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'];

理想的单词表具有以下特点:

  • 巧妙选词:单词表的创建方式为键入前四个字母足以来明确地标识单词;
  • 类似词避免:像"build"和"built","woman"和"women",或"quick"和"quit"这样的词对不仅使记忆句子变得困难,而且更容易出错,更难猜测;
  • 对词库进行分类:wordlist是排序的,这样可以更有效地查找代码(即实现可以使用二进制搜索代替线性搜索),也允许使用trie(前缀树),例如为了更好的压缩。

然后,生成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文件解密账号,首先读取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可以发现这两者是一样的。

之后使用给定私钥创建账户的方法就行。

点赞 3
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
阳光灿烂
阳光灿烂
江湖只有他的大名,没有他的介绍。