还记得我们创建比特币钱包时的场景吗?其中有一步操作,要求我们拿出纸笔,把屏幕上出现的一系列单词(有时称助记符,有的软件叫Seed Words)按顺序抄在纸张上,并提示我们保管好,因为这些单词是恢复钱包的唯一手段。
如果你对比特币有一定的了解,当你在看到这些助记符时肯定会产生疑惑,因为通常人们理解的是:只有私钥才需要保管,且只有私钥才能恢复钱包,但创建钱包时并没有要求你保存私钥,而是记录一些助记符,那么我们很容易的做出推断——私钥和助记符之间一定有着某种联系。
我和助记符的故事
那为了验证这种联系,在没有搞清楚助记符背后的逻辑之前,通常的做法是验证这些助记符是否能像私钥一样恢复钱包
很多人一开始应该和我一样,很少考虑钱包的事情,然后把代币都托管在交易所的钱包上,但9月4日之后,我开始陆续把资产转移到自己的钱包,记得第一次使用比特币钱包,我先转了一笔价值不到100元的比特币到钱包上,然后在钱包上把这个账号删掉,接着使用助记符恢复这个钱包,在确认能够恢复后,才放心的把剩余代币转移过去。
我还记得当初花了2个小时来折腾这个事儿,因为我使用的是trezor钱包,trezor在恢复时会故意打乱助记符的顺序,由于忽视了这一点,导致多浪费了不少时间。实际上,如果你理解了助记符的原理,你完全不需要再花时间来反复验证了。
种子
那么助记符到底是怎么回事呢,在介绍助记符之前,我们要先说一个概念——种子(Seed),实际上比特币钱包往往不会直接保存私钥,而是保存一个“种子”(Seed)数据,步骤大致如下:
- 产生种子数据
- 用种子算出一个账号数据
- 通过这个账号,可以产生无数个私钥
其中从第1步到第2步,只要种子不变,通过种子算出的账号也是不变的。
而第3步中,你可以给每个产生的私钥分配一个序号,例如0、1、2等,只要序号确定,那么私钥的数值就是一定的。这也是为什么我们可以在钱包里创建多个账号的原因,这么多账号虽然都各自拥有一对公、私钥,但我们只需要一个种子,就可以把它们全部恢复,你说是不是很神奇,保存种子比直接保存私钥效率要高很多。
下面我们通过一个程序(bitcoin explorer是一个比特币命令行工具)来观察一下整个过程(符号 '#' 右边的文字是我的解释):
- 产生种子数据
$ bx seed
00654f0bbd1721b75bbe54e29fdbf755523ab435708336ad
- 产生account数据,你可以把这一步重复多次,然后会观察到产生的结果是一样的
# 产生master数据
$ bx hd-new 00654f0bbd1721b75bbe54e29fdbf755523ab435708336ad
xprv9s21ZrQH143K4VHVZmdpHhfRKmZ4fnySJBpNaSpkC7UfA3wNiMzN714ga5BSqXhdGDJCaMvW5Ww176mnuTsB4pFurk2fNrnsNhYS4igVrkS
# 产生account数据
$ bx hd-private --hard xprv9s21ZrQH143K4VHVZmdpHhfRKmZ4fnySJBpNaSpkC7UfA3wNiMzN714ga5BSqXhdGDJCaMvW5Ww176mnuTsB4pFurk2fNrnsNhYS4igVrkS
xprv9uUeTjMk9f3C2u7sEUzBqtWWJ9AekeHAy1pfjq5X19nKW5qqyiUr5LBHp87bHSyNSMRT9ehaBP4H5A21AVSzFhjiqvxbDMfTQfhYD6Hh3xV
- 通过account数据,你就可以按照序号来产生私钥了,同样你也可以多试几次,并观察同样的序号,产生的私钥是否是一致的
# 序号0
$ bx hd-private --index 0 xprv9uUeTjMk9f3C2u7sEUzBqtWWJ9AekeHAy1pfjq5X19nKW5qqyiUr5LBHp87bHSyNSMRT9ehaBP4H5A21AVSzFhjiqvxbDMfTQfhYD6Hh3xV
xprv9xcBDpHwSSEXHBCMqTcMSGooQjLgYKXxkMN9cdVWV9HJKVBzgMhk1kXy1WdsfG9FT1SzATjAPguZjGj6LoBhLBd7tyKz2EA2xixX6uxAuVN
# 序号1
$ bx hd-private --index 1 xprv9uUeTjMk9f3C2u7sEUzBqtWWJ9AekeHAy1pfjq5X19nKW5qqyiUr5LBHp87bHSyNSMRT9ehaBP4H5A21AVSzFhjiqvxbDMfTQfhYD6Hh3xV
xprv9xcBDpHwSSEXLjzaSkjq8khKHKR1BsXHWVZhz14VNZsM5eWyjYVwhwsjnLHJaHXD4EXrTSM1N3JzWJU8jqNrmF4sdpFiTEGsh1MkNUR6TUy
助记符
现在你再知道钱包是如何保存私钥了的吧,但这还没完,设想一个场景,在助记符出现之前,我们要备份账号就一定要记下种子,而你也看到了,种子是一串长长的字符串,它没有任何意义,人们在记录它的时候会很容易出错,助记符就是为了解决这个问题而生的。
从整个产生私钥的过程来说,要引入了更容易记录的助记符,只需调整一下种子的生成过程:
让种子的生成算法仅依赖于助记符
通过示意图,可以看到所做的调整是:用算法生成助记符,再通过助记符产生种子,后面的步骤保持不变。
下面我们再用命令来演示下如何产生助记符,及它是如何产生种子的
# 创建一个用来生成助记符的种子
$ bx seed
b03e3cf733130570068147160b80a117078ed3c9459dc2d2
# 创建助记符
$ bx mnemonic-new b03e3cf733130570068147160b80a117078ed3c9459dc2d2
rabbit vehicle differ great core retreat borrow cigar bid foster choose come jump hazard celery recipe security motion
# 通过助记符创建一个用来生成私钥的种子
$ bx mnemonic-to-seed rabbit vehicle differ great core retreat borrow cigar bid foster choose come jump hazard celery recipe security motion
488e65727e3bf0440cee45863961828a2de2963c14e2124740c6e18d5c0c61a7c661760aa8fc82141af5c023e69a997d88ef1f1204eeef9e90e323dc76cfcdc6
同样的,对于相同的助记符,你可以多执行几次bx mnemonic-to-seed
命令,看看产生的种子是否都是一致的,可以推断,恢复钱包的过程就是从这条命令开始的。
最后,如果你有一定的编程基础,建议你去阅读一下Bitcoin Explorer的源码(这套代码的组织结构非常清晰),可以更深入的理解背后的密码学原理。