助记词顺序乱了怎么找回

前言

数月前我换手机后还原加密钱包时,发现当初备份的助记词缺少 1 位单词,险些导致资产丢失,最后通过研究文档和实现原理,搞定了助记词的生成、加密钱包地址的生成算法,最终写了个程序找回了丢失的那个单词,详情记录在这篇博客里:

Ethan Zhou:加密钱包助记词丢失后的一天3 赞同 · 4 评论文章

后来有几个朋友找到我,说也遇到了助记词相关的问题,有丢失 1 位的,有丢失2位的,甚至有抄错好几个单词,还把最后两个单词漏掉的!我后面优化了好几个版本代码,都帮他们找回了。

正文

最近遇到了情况,就是12个助记词都在,但是导入时候提示无效助记词,然后随便换一下顺序就可以登录上去,说明单词本身都是有效的,对方觉得可能是助记词顺序抄错导致的,希望我能帮他把这 12 个助记词的所有可能的排列组合都计算出来并生成对应的地址,这样他用自己的地址匹配一下,就能找到正确的助记词了。

这就是个全排列问题,我算了一下,12 个助记词有 12! = 479,001,600 个组合,对现在的计算机来说这是小 case, 因为是 cpu 密集型计算,关键是还要对每个组合生成钱包地址,这个很耗时间,因为涉及第三方库 Api,属于 IO 密集型操作,需要异步等待,到底完整流程走完耗时多少心里也没谱,于是我做了个测试,在我的 macbook pro 14(m1 pro芯片)上,可以达到 1000次/秒,那么完整跑完程序需要 5.5 天时间,虽然慢了点,不过证明还是可行的,如果 1秒只能生成几个地址那才是真的完蛋。

初版程序写完后,先给朋友电脑上配好环境跑着,我自己又开始琢磨有没有办法提高 地址生成的效率,上网查了一通果然有收获,原来不同的算法实现效率不一样的,之前我用的是 `ethereumjs-wallet` 这个库提供的生成算法,在我电脑上只能跑到 1000次/秒。

async function getAddressFromMnemonic(mnemonic) {
  const seed = await bip39.mnemonicToSeed(mnemonic);
  const hdk = hdkey.fromMasterSeed(seed);
  const addrNode = hdk.derivePath("m/44'/60'/0'/0/0");
  const wallet = addrNode.getWallet();
  return `0x${wallet.getAddress().toString('hex')}`;
}

听说还有个 `ECDSA 椭圆算法` ,于是研究了下, 需要使用 `ethers` 这个库,并且注意如果是 6以上的版本,需要用 `fromPhrase` 方法。

async function getAddressFromMnemonic(mnemonic) {
  const wallet = ethers.Wallet.fromPhrase(mnemonic);
  return wallet.address;
}

效果如下图所示,速度已经达到了 3500+ 次每秒,比初版程序快了 3 倍。

注意,以上说的时间是全部执行完,需要消耗的时间,实际上我们不需要完整跑完,每生成一个地址,就可以和我们自己的地址匹配一下,如果一样,就可以提前终止程序了,运气好的话(顺序错的是尾部的几个单词),几秒钟就找回也是有可能的

当然还有进一步优化的空间,就是使用多线程,不过我用 node 写的,不知为何多线程跑起来速度没感觉有提升,容我后续再想想。


欢迎技术讨论 v: 1032151090

文章更新平台:掘金知乎Github、公号【编码美学】。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值