什么是分层确定性钱包(HD Wallet)| 骁哥手记

深入探讨 HD Wallet 的技术原理

作者:

日期: 2020.11.12

阅读时长: 5 分钟

前言

最近在看Filecoin应用,学习Filecoin的交易和签名工具,第一步就是导入HD Wallet。原以为这个出现在上古圣经《精通比特币》书中的概念早已人人尽知,实际调研后却发现中文技术社区的文章大多是BIP32的直接翻译,或是简单的接口使用讨论,更深入的问题如:“加固派生密钥为什么安全?”并没有被讨论。本文记录一下我关注的问题和理解,为希望进一步了解HD Wallet原理的朋友提供一些参考。

HD Wallet的由来

HD Wallet是分层确定性(Hierarchical Deterministic)钱包的简写。在HD Wallet出现之前,比特币钱包是通过随机数生成互不相关的多个私钥。这种类型的钱包被称作非确定钱包(或随机钱包)。

在中本聪的UTXO模型中,客户端默认是每个比特币地址只能用一次交易,因此钱包使用过程中需要反复备份、导入再使用密钥进行签名交易,非常不便。

为了解决非确定性钱包的私钥管理问题,社区成员提出了一种使用“种子”使用哈希函数单向生成一组的私钥的方法。并在这种思想的基础上,增加了密钥派生(BIP32)、助记词(BIP39)、派生路径规范(BIP43/44)等功能,形成了现在统一规范的HD wallet。

BIP32和它小伙伴们

BIP32是分层确定性钱包的核心改进,它基于严谨的密码学算法提出了一套先进的钱包管理方法。在BIP32刚提出来的年代,确定性钱包有两种主要类型:Electrum钱包和BIP32钱包;这两种钱包的算法和设计接近,但最终BIP32钱包成为了后来的标准。

BIP39是比特币HD Wallet规范中最贴近用户的。只要使用过数字钱包的用户都会对它有印象,还记得手抄的私钥词组吗?它通过一组易于记忆的单词(助记词)来生成确定性钱包的种子密钥。

BIP43和BIP44统一了钱包软件对分层路径和数字编号的理解和使用,使得了用户用相同的助记词在同一区块链中能够确定性地生成相同的一组密钥。

BIP39、BIP43、BIP44都是兼容BIP32的协议,后来还被比特币以外的区块链所借鉴,形成了区块链行业的共识。本文重点关注密钥派生BIP32的细节问题,其他改进协议不一一展开介绍。

BIP32相关疑问

第一次阅读《精通比特币》时,大多数人对密码学的知识可能还是一知半解,对于超过理解范围的知识可能会选择跳过或抓住结论、忽略过程。所以会得出对HD Wallet的第一层理解:

HD钱包就是通过hash算法逐层衍生私钥,得到用一个种子(或助记词)管理无数多密钥的方法。

当再次翻看这章节时,关注到专用名词“扩展密钥“,得出HD Wallet的第二层理解:

HD钱包有一种设计,实现了父私钥派生子私钥,父公钥派生子公钥,子私钥和子公钥是“一对密钥”。

不禁提出疑问:

“父私钥”生成“子私钥”、“父公钥”生成“子公钥”,这是用某种神奇的算法实现?还是某种协议约定?或是整个系统里只用到一个“真-私钥”,而“子私钥”和“扩展密钥”只是定义出来的抽象的概念而已呢?

确定性钱包的特点

我们说确定性钱包有两个直观特点:

  1. 可以通过父密钥获取子密钥(包括:父私钥获取子私钥、父公钥获取子公钥),但反之不成立;
  2. 可以公开主公钥,而不必担心资金损失。

宣传此特点的主要场景是在分层的组织中,比如公司将子私钥交给部门,将子公钥交给会计师和审计师,而将根私钥交给财务主管。这种算法带来的近乎神奇的功能,让许多人(包括懂技术的人)将HD Wallet的功能神化。但这样对分层钱包的描述存在致命的缺陷。

这一缺陷也是我对HD Wallet的第三层理解:尽管可以安全地分发子私钥而对父私钥没有风险,也可以分发主公钥而对主私钥没有风险,但是不能同时进行这两种操作。其中的风险隐藏在分层确定性钱包的算法中,在介绍这一缺陷之前,我们先研究一下BIP32和密钥派生函数。

BIP32规范

为了更准确介绍BIP32的定义和内涵,我建议计算机专业背景的读者直接阅读。

BIP32规范中用了许多密码学公式来定义HD Wallet如何派生密钥,对于非计算机专业的同学不太友好。我们这里抛开密码学的严谨定义和推导,用白话描述BIP32规范。

BIP32主要介绍了三个概念:密钥派生函数、密钥树和主密钥生成。

密钥派生函数(Child Key Derivation function)

密钥派生函数是一个经过特殊设计的函数,核心部分是使用消息认证码HMAC-SHA512(本质上是先对数据进行Hash,再进行对称加密)。HMAC-SHA512有个特点,就是当知道输入Data和Key时,能够得到输出I;仅知道输出I和输入Key,不能推导出Data。

            `I = HMAC-SHA512(Key, Data)`

父层的 I 决定分别取前32位和后32位作为拓展私钥和加密密钥,Key即使用加密密钥,Data由拓展私钥(或拓展公钥)和数字编号i经过简单的拼接得到。

然后通过严谨的算法证明,得出我们先前提到的结论:父私钥派生出子私钥,父公钥派生出子公钥,子私钥和子公钥是一对密钥。(参考下图)

image-20201112222504223

此外,区别与一般密钥派生函数,人为设计了另一种函数“加硬”密钥派生。这里用数字编号i的首位(共32位)作为标识。当首位为0,即数字编号i < 2^31,采用一般密钥派生函数。首位为1,即i >= 2^31时,采用“加硬”密钥派生函数。对于“加硬”密钥派生函数,无论是获得子私钥还是子公钥,都需要使用父私钥进行派生计算,所以它失去了一般密钥派生函数中公钥直接派生公钥的特性,变得不灵活了,同时也更安全了,“加硬”了。后面会介绍加硬密钥的使用场景。

image-20201114123044822

密钥树

由于密钥派生关系是可以多层迭代的,因此可以使用一个密钥多层级派生,构建出树形密钥层级结构。如果是普通密钥派生关系,公钥派生子公钥的特性也可以逐层传递。当某一层的密钥派生关系是“加硬”的,则这种传导关系就中止了。用公式可以表示为:

  • N(m/a/b/c) = N(m/a/b)/c = N(m/a)/b/c = N(m)/a/b/c = M/a/b/c.
  • N(m/aH/b/c) = N(m/aH/b)/c = N(m/aH)/b/c.

H表示加硬密钥派生

image-20210203164925524

主密钥生成

前面说了密钥的派生功能和多层级派生关系,BIP32中还初步讨论了种子密钥和主密钥生成的方式。如上图种子可以是任意长度的值,经过一次HMAC-SHA512计算得到主密钥。

BIP32建议使用一个PNG文件来处理种子数据的随机性问题。BIP32的小伙伴们,BIP39、BIP43、BIP44在主密钥生成方面做了更进一步的规范。

BIP32安全讨论

BIP32的安全问题是着手写这篇文章的动机之一。BIP32中一个已知的漏洞是前文提到的同时分发父公钥和子私钥情况下,父私钥将处于危险之中。在2013年,Vitalik在Bitcoinmagazine的中已经指出这一风险,并使用代码进行论证。他分别对Electrum钱包和BIP32钱包进行测试,结果显示,通过已知父公钥和子私钥,不仅可以获得同级对其他子私钥,还可以破解得出父私钥。

wp = bip32_privtopub(w) w0 = bip32_ckd(w,0) crack_bip32_privkey(wp,w0) 'xprv9s21ZrQH143K2KhRQVuMqhz798mvW89J1aJMWEKNfZzv3BPAgBc4TH59K8ZcLt8RrNJvbUzA72A92Grm3MorG2FnFaoZ7B8SDTYXgUBALoi'因此,在密钥的分级管理中,当有可能同时透露父公钥和子私钥的情况下,不应该使用一般密钥派生方式,可以使用“加硬”密钥派生方式。

防范这个漏洞,公司或组织在使用BIP32的层级钱包时需要格外注意。对于一般用户,不必对HD Wallet的安全过于担心。因为相关的约定规范了钱包的派生流程,考虑的加硬的环节,同时,个人使用场景一般不涉及子密钥分发的问题,所以HD Wallet钱包进行密钥管理仍是安全的第一选择。

总结

HD Wallet是当下主流数字钱包的首选。作为用户,在不同的钱包App中能够轻松的管理好自己的密钥;作为开发者,它提供了一套现成的、多语言的开发工具,降低了钱包软件的开发成本。作为想深入研究钱包原理,同时希望利用分层钱包特性设计一些创新场景的产品经理,需要注意设计时的安全考量,避免大规模使用后的密钥泄露问题。

参考文献

  1. 精通比特币
  2. BIP32.
  3. Private Key Recovery Combination Attacks...
  4. HD 钱包详解:Part 2——BIP32 注解.
  5. Vitalik. Deterministic Wallets, Their Advantages And Their Understated Flaws.
  6. 千里之堤毁于蚁穴(慎用HD Wallets).

本文参与2022世界杯预选赛赛程直播社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 2021-02-07 22:30
  • 阅读 ( 874 )
  • 学分 ( 5 )
  • 分类:FileCoin

0 条评论

请先 登录 后评论
李大狗
李大狗

上海对外经贸大学区块链研究中心副主任

53 篇文章, 5937 学分