第五章. 钱包恢复

  • berry
  • 发布于 2025-02-07 17:19
  • 阅读 12

第五章. 钱包恢复

综合介绍

创建私钥和公钥对是使比特币钱包能够接收和花费比特币的关键部分。但是,如果丢失了私钥,任何人都无法再花费相应的公钥接收到的比特币。 多年来,钱包和协议开发人员一直致力于设计系统,使用户能够在出现问题后恢复对比特币的访问,而不会在其他时间损害安全性。

在本章中,我们将探讨钱包采用的一些不同方法,以防止数据丢失导致资金损失。一些解决方案几乎没有缺点,并被现代钱包普遍采用。我们将简单地将这些解决方案推荐为最佳实践。其他解决方案既有优势也有劣势,导致不同的钱包作者做出不同的权衡。在这些情况下,我们将描述各种可用的选项。

独立密钥生成

物理现金的钱包持有现金,因此许多人错误地认为比特币钱包包含比特币。事实上,许多人称为比特币钱包的东西(我们称之为钱包数据库,以区别于钱包应用程序)只包含密钥。这些密钥与记录在区块链上的比特币相关联。通过向比特币全节点证明你控制这些密钥,你可以花费相关的比特币。

简单的钱包数据库包含接收比特币的公钥以及允许创建授权支出这些比特币所需的私钥。其他钱包的数据库可能仅包含公钥,或者仅包含授权支出交易所需的某些私钥。它们的钱包应用程序通过与外部工具(如硬件签名设备或多重签名方案中的其他钱包)合作来生成必要的签名。

钱包应用程序可以独立生成后续计划使用的每个钱包密钥,如图5-1所示。所有早期的比特币钱包应用程序都这样做,但是用户需要在每次生成和分发新密钥时备份钱包数据库,这可能频繁到每次生成新地址以接收新支付时。如果未能及时备份钱包数据库,用户将无法访问未备份的密钥收到的任何资金。

对于每个独立生成的密钥,用户需要备份大约32字节,再加上开销。一些用户和钱包应用程序尝试通过仅使用单个密钥来最小化需要备份的数据量。虽然这样做可能是安全的,但严重降低了该用户及其所有交易对象的隐私。重视隐私的人和他们的同行为每笔交易创建新的密钥对,生成的钱包数据库只能合理地使用数字媒体进行备份。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/5.1.png" alt=""><figcaption><p>图 5-1. 非确定性密钥生成:存储在钱包数据库中的一组独立生成的密钥。</p></figcaption></figure>

现代钱包应用程序不会独立生成密钥,而是使用可重复(确定性)算法从单个随机种子派生密钥。

确定性密钥生成

当给定相同的输入时,哈希函数总是会产生相同的输出,但是如果输入稍有改变,输出将会不同。如果函数是加密安全的,那么没有人应该能够预测新的输出,即使他们知道新的输入。

这使我们能够将一个随机值转换为几乎无限数量的看似随机值。更有用的是,稍后使用相同的哈希函数和相同的输入(称为种子)将产生相同的看似随机值:

## Collect some entropy (randomness)
$ dd if=/dev/random count=1 status=none | sha256sum
f1cc3bc03ef51cb43ee7844460fa5049e779e7425a6349c8e89dfbb0fd97bb73 -
## Set our seed to the random value
$ seed=f1cc3bc03ef51cb43ee7844460fa5049e779e7425a6349c8e89dfbb0fd97bb73
## Deterministically generate derived values
$ for i in {0..2} ; do echo "$seed + $i" | sha256sum ; done
50b18e0bd9508310b8f699bad425efdf67d668cb2462b909fdb6b9bd2437beb3 -
a965dbcd901a9e3d66af11759e64a58d0ed5c6863e901dfda43adcd5f8c744f3 -
19580c97eb9048599f069472744e51ab2213f687d4720b0efc5bb344d624c3aa -

如果我们将这些派生的值用作我们的私钥,那么稍后我们可以使用之前使用的算法和我们的种子值生成完全相同的私钥。使用确定性密钥生成的用户可以通过简单地记录他们的种子和他们使用的确定性算法的引用来备份他们钱包中的每个密钥。例如,即使Alice有一百万个比特币分别存放在一百万个不同的地址中,她只需要备份以下内容,以便稍后恢复对这些比特币的访问:

f1cc 3bc0 3ef5 1cb4 3ee7 8444 60fa 5049

e779 e742 5a63 49c8 e89d fbb0 fd97 bb73

基本顺序确定性密钥生成的逻辑图如图5-2所示。然而,现代钱包应用程序有一种更聪明的方法来实现这一点,允许公钥与其相应的私钥分别派生,从而使得私钥比公钥更安全地存储成为可能。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/5.2.png" alt=""><figcaption><p>图 5-2. 确定性密钥生成:从钱包数据库的种子派生出的确定性密钥序列。</p></figcaption></figure>

子公钥派生

在第59页的“公钥”部分,我们学习了如何使用椭圆曲线密码学(ECC)从私钥创建公钥。虽然在椭圆曲线上的操作并不直观,但它们类似于常规算术中使用的加法、减法和乘法操作。换句话说,可以对公钥进行加法、减法或乘法操作。考虑我们在第59页的“公钥”部分中使用的操作,用主私钥(k)和生成器点(G)生成公钥(K):

K = k × G

通过简单地将相同的值添加到等式的两边,可以创建一个派生密钥对,称为子密钥对:

K + 123 × G == k + 123 × G

注意:在本书中的方程中,我们使用单个等号表示诸如 K = k × G 这样的操作,其中计算了变量的值。我们使用双重等号来显示方程两边是等价的,或者如果两边不等价,则操作应返回 false(而不是 true)。

这样做的一个有趣的结果是,可以使用完全公开的信息将123添加到公钥中。例如,Alice生成了公钥K并将其提供给Bob。Bob不知道私钥,但他知道全局常数G,因此他可以向公钥添加任何值,以生成一个派生的公共子键。然后,如果他告诉Alice他向公钥添加的值,她可以将相同的值添加到私钥中,从而生成与Bob创建的公共子键相对应的派生私有子键。

换句话说,即使你不知道父私钥的任何信息,也可以创建子公钥。添加到公钥的值称为密钥调整值。如果使用确定性算法来生成密钥调整值,那么即使某人不知道私钥,也可以从单个公共父键创建一系列基本上无限的公共子键。控制私有父键的人可以使用相同的密钥调整值创建所有相应的私有子键。

这种技术通常用于将钱包应用的前端(不需要私钥)与签名操作(需要私钥)分离。例如,Alice的前端向想要支付她的人分发她的公钥。稍后,当她想要花费收到的钱时,她可以向硬件签名设备(有时令人困惑地称为硬件钱包)提供她使用的密钥调整值,该设备安全地存储她的原始私钥。硬件签名者使用这些调整值来推导所需的子私钥,并使用它们来签名交易,然后将已签名的交易返回给较不安全的前端以广播到比特币网络。

公共子键派生可以产生与先前看到的图5-2类似的线性键序列,但现代钱包应用程序使用一种更巧妙的技巧来提供键树而不是单个序列,如下一节所述。

分层确定性(HD)密钥生成(BIP32)

我们所知道的每个现代比特币钱包默认都使用分层确定性(HD)密钥生成。这个标准在BIP32中定义,使用确定性密钥生成和可选的公共子密钥派生算法,生成一组密钥的树。在这个树中,任何密钥都可以是一系列子密钥的父密钥,而这些子密钥中的任何一个都可以是另一系列子密钥(原始密钥的子孙)的父密钥。树的深度没有任何任意限制。这种树结构如图5-3所示

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/5.3.png" alt=""><figcaption><p>图 5-3. HD钱包:从单个种子生成的密钥树</p></figcaption></figure>

树结构可以用来表示额外的组织含义,比如特定的子密钥分支用于接收传入付款,另一个分支用于接收传出付款的找零。密钥的分支也可以在企业设置中使用,将不同的分支分配给部门、子公司、特定功能或会计类别。

我们将在“从种子创建HD钱包”一节中进行对HD钱包的详细探讨。

种子和恢复码

HD钱包是一种非常强大的机制,可以管理从单个种子派生出的许多密钥。如果你的钱包数据库曾经损坏或丢失,你可以使用原始种子重新生成钱包的所有私钥。但是,如果其他人获取了你的种子,他们也可以生成所有的私钥,从而能够窃取单签名钱包中的所有比特币,并降低多重签名钱包中比特币的安全性。在本节中,我们将讨论几种恢复码,旨在使备份更加简便和安全。

虽然种子是大型随机数,通常为128至256位,但大多数恢复码使用人类语言单词。使用单词的主要动机之一是使恢复码易于记忆。例如,考虑使用十六进制和单词编码的恢复码,如示例5-1所示。

示例5-1。一个以十六进制和英语单词编码的种子

Hex-encoded:

0C1E 24E5 9177 79D2 97E1 4D45 F14E 1A1A

Word-encoded:

army van defense carry jealous true garbage claim echo media make crunch

可能存在一些情况,记住恢复码是一个强大的功能,比如当你无法携带物理财产(比如写在纸上的恢复码),以免它们被外部可能窃取你比特币的当事人扣押或检查。然而,大多数情况下,仅依赖记忆是危险的:

  • 如果你忘记了恢复码并且无法访问原始的钱包数据库,你的比特币将永远丢失。
  • 如果你死亡或遭受严重伤害,你的继承人没有访问你原始钱包数据库的权限,他们将无法继承你的比特币。
  • 如果有人认为你记住了一个恢复码,可以让他们访问比特币,他们可能会试图强迫你透露该代码。 截至撰写本文时,比特币贡献者詹姆逊·洛普(Jameson Lopp)记录了100多起针对比特币和其他数字资产的潜在所有者的物理攻击,包括至少三起死亡案件和许多事件,其中有人遭受折磨、被扣为人质,或者家人受到威胁。

注意:即使你使用设计用于轻松记忆的恢复码类型,我们强烈建议你考虑将其写下来。

截至撰写本文时,有几种不同类型的恢复码正在广泛使用:

BIP39

作为过去十年生成恢复码最流行的方法,BIP39涉及生成一个随机的字节序列,为其添加一个校验和,然后将数据编码成一系列12到24个单词(可以根据用户的母语进行本地化)。这些单词(加上一个可选的密码)经过一种键拉伸函数处理,输出被用作种子。BIP39恢复码有几个缺点,后来的方案试图解决这些问题。

Electrum v2

在Electrum钱包(版本2.0及以上)中使用的这种基于单词的恢复码比BIP39具有几个优点。它不依赖于一个全球性的单词列表,该列表必须由每个兼容程序的每个版本实现,而且其恢复码包括一个版本号,提高了可靠性和效率。与BIP39类似,它支持一个可选的密码(Electrum称之为种子扩展),并使用相同的键拉伸函数。

Aezeed

在LND钱包中使用的这种基于单词的恢复码比BIP39有所改进。它包括两个版本号:一个是内部版本号,消除了升级钱包应用程序(如Electrum v2的版本号)时的一些问题;另一个版本号是外部的,可以递增以改变恢复码的底层加密属性。它还在恢复码中包含了一个钱包生日,即用户创建钱包数据库的日期的参考。这允许恢复过程找到与钱包关联的所有资金,而无需扫描整个区块链,这对于注重隐私的轻量级客户端特别有用。它支持更改密码或更改恢复码的其他方面,而无需将资金转移到新的种子——用户只需备份一个新的恢复码。与Electrum v2相比的一个缺点是,与BIP39一样,它取决于备份和恢复软件支持相同的单词列表。

Muun

Muun钱包使用的是非单词代码,该钱包默认要求多个密钥签名来进行交易,必须与其他额外信息一起使用(Muun目前提供在PDF文件中)。这个恢复码与种子无关,而是用于解密PDF中包含的私钥。虽然与BIP39、Electrum v2和Aezeed恢复码相比,这种方法相对麻烦,但它支持新技术和标准,这些技术和标准在新钱包中变得越来越普遍,如闪电网络(LN)支持、输出脚本描述符和小脚本。

SLIP39

SLIP39是BIP39的一个继任者,由一些相同的作者编写,它允许使用多个恢复码来分发单个种子,这些恢复码可以存储在不同的地方(或由不同的人保存)。当你创建恢复码时,可以指定需要多少个来恢复种子。例如,你创建了五个恢复码,但只需要其中三个来恢复种子。SLIP39支持可选的密码,依赖于一个全局的单词列表,并且不直接提供版本控制。

注意:一种类似于SLIP39的新的分发恢复码系统在书写过程中被提出。Codex32允许只使用打印说明书、剪刀、精密刀、黄铜卡扣和笔即可创建和验证恢复码,再加上隐私和一些空闲时间。另外,那些信任计算机的人可以使用数字设备上的软件立即创建恢复码。你可以创建多达31个恢复码,并将它们存储在不同的地方,指定需要多少个恢复码才能恢复种子。作为一个新的提议,Codex32的详细信息在本书出版前可能会发生重大变化,因此我们鼓励对分布式恢复码感兴趣的读者调查其当前状态。

恢复码密码

BIP39、Electrum v2、Aezeed 和 SLIP39 方案都可以与可选的口令一起使用。如果你唯一保存口令的地方是你的记忆中,那么它具有与记忆恢复码相同的优点和缺点。然而,还有一组针对口令在恢复码中使用方式的特定权衡。

这三种方案(BIP39、Electrum v2 和 SLIP39)在用于防止数据输入错误的校验和中不包括可选的口令。每个口令(包括不使用口令)都将产生一个用于 BIP32 密钥树的种子,但它们不会是相同的树。不同的口令将产生不同的密钥。这可能是积极的或消极的,这取决于你的观点:

• 积极的一面是,如果有人获取了你的恢复码(但没有你的口令),他们将看到一个有效的 BIP32 密钥树。如果你为这种可能性做好了准备,并向非口令树发送了一些比特币,那么他们将窃取那笔钱。尽管有些比特币被盗通常是一件坏事,但它也可以提醒你恢复码已被泄露,从而让你调查并采取纠正措施。为相同的恢复码创建多个口令,所有这些口令看起来都有效,这是一种合理的否认的类型。

• 消极的一面是,如果你被迫向攻击者提供恢复码(带有或不带有口令),但它没有产生他们期望的比特币数量,他们可能会继续试图强迫你,直到你给出另一个口令,以访问更多的比特币。设计合理的否认意味着没有办法向攻击者证明你已经泄露了所有信息,因此即使在你给出所有比特币后,他们可能会继续试图强迫你。

• 另一个负面因素是错误检测的减少。如果在从备份恢复时输入了略有错误的口令,你的钱包将无法警告你有关错误。如果你期望有余额,当你的钱包应用程序为重新生成的密钥树显示零余额时,你会知道出现了问题。然而,新手用户可能会认为他们的钱永远丢失了,并做出愚蠢的事情,比如放弃并丢掉他们的恢复码。或者,如果你实际上期望零余额,那么在你犯错后的几年里,你可能会继续使用钱包应用程序,直到下次使用正确的口令进行恢复并看到零余额。除非你能够找出先前犯下的拼写错误,否则你的资金将不复存在。

与其他方案不同,Aezeed 种子加密方案对其可选口令进行身份验证,并在提供错误值时返回错误。这消除了合理的否认,增加了错误检测,并使得可以证明口令已被泄露。

许多用户和开发人员对哪种方法更好存在不同意见,有些人坚决支持合理的否认,而其他人则更喜欢增加安全性,以便新手用户和受压迫者。我们认为,只要恢复码继续被广泛使用,这种辩论就会持续下去。

备份非密钥数据

钱包数据库中最重要的数据是其私钥。如果你无法访问私钥,你将无法花费比特币。确定性密钥派生和恢复码为备份和恢复你的密钥及其控制的比特币提供了一个相当健壮的解决方案。然而,重要的是要考虑到许多钱包数据库存储的不仅仅是密钥,它们还存储了关于每笔交易的用户提供的信息。

例如,当 Bob 在向 Alice 发送发票的一部分时创建一个新地址时,他会向他生成的地址添加一个标签,以便他可以区分她的付款与他收到的其他付款。当 Alice 支付 Bob 的地址时,她也会将交易标记为支付给 Bob 的原因相同。一些钱包还会向交易中添加其他有用的信息,例如当前的汇率,在某些司法管辖区计算税收时可能很有用。这些标签完全存储在它们自己的钱包中,而不与网络共享,保护了它们的隐私,并将不必要的个人数据排除在区块链之外。请参阅表 5-1 中的示例。

表 5-1. Alice 的每笔交易历史及其标记

日期 标签 BTC
2023-01-01 Bought bitcoins from Joe +0.00100
2023-01-02 Paid Bob for podcast −0.00075

然而,由于地址和交易标签仅存储在每个用户的钱包数据库中,并且因为它们不是确定性的,所以它们不能仅通过使用恢复码来恢复。如果唯一的恢复方式是基于种子的,那么用户将只能看到一个近似的交易时间和比特币金额的列表。这可能会让人很难弄清楚过去如何使用自己的钱。想象一下回顾一年前的银行或信用卡对账单,上面列出了每笔交易的日期和金额,但“描述”字段为空白。

钱包应该为用户提供一种方便的方式来备份标签数据。这似乎是显而易见的,但有许多广泛使用的钱包应用程序可以轻松创建和使用恢复码,但却没有提供备份或恢复标签数据的方式。

此外,钱包应用程序提供一种标准化格式导出标签可能会很有用,以便它们可以在其他应用程序(例如会计软件)中使用。该格式的标准提议在BIP329中。

钱包应用程序实现了超出基本比特币支持的其他协议,可能也需要或希望存储其他数据。例如,截至2023年,越来越多的应用程序已经添加了支持通过闪电网络(LN)发送和接收交易的功能。尽管闪电网络协议提供了一种在数据丢失时恢复资金的方法,称为静态通道备份,但它无法保证结果。如果你的钱包连接的节点意识到你丢失了数据,它可能会窃取你的比特币。如果它在你丢失数据库的同时丢失了其钱包数据库,并且你两者都没有充足的备份,那么你两者都将损失资金。

再次强调,这意味着用户和钱包应用程序需要做的不仅仅是备份恢复码。

一些钱包应用程序实现的解决方案是频繁地自动创建完整的备份,将其钱包数据库加密,加密密钥是从其种子派生的。比特币密钥必须是无法猜测的,而现代加密算法被认为是非常安全的,因此除了能够生成种子的人之外,没有人应该能够打开加密备份。这使得在不受信任的计算机上存储备份成为可能,例如云托管服务甚至是随机网络节点。

稍后,如果原始的钱包数据库丢失了,用户可以将其恢复码输入到钱包应用程序中以恢复其种子。然后,应用程序可以检索最新的备份文件,重新生成加密密钥,解密备份,并恢复用户的所有标签和其他协议数据。

备份密钥派生路径

在BIP32密钥树中,大约有40亿个一级密钥;每个这些密钥都可以有自己的40亿个子级,而每个子级又可以有自己的40亿个子级,依此类推。钱包应用程序不可能生成BIP32树中的所有可能密钥的一小部分,这意味着从数据丢失中恢复需要知道的不仅仅是恢复码、获取种子的算法(例如,BIP39)和确定性密钥派生算法(例如,BIP32) - 还需要知道你的钱包应用程序用于生成其分发的特定密钥的密钥树中的路径。

已经采用了两种解决方案来解决这个问题。第一种是使用标准路径。每当与钱包应用程序可能想要生成的地址相关的变化发生时,某人都会创建一个BIP,定义要使用的密钥派生路径。例如,BIP44定义了m/44'/0'/0'作为用于P2PKH脚本(传统地址)中的密钥的路径。实现此标准的钱包应用程序在首次启动时和从恢复码进行恢复后都使用该路径中的密钥。我们称这种解决方案为隐式路径。由BIP定义的几个流行的隐式路径如表5-2所示。

表5-2. 由各种BIP定义的隐式脚本路径

标准 脚本 BIP32路径
BIP44 P2PKH m/44'/0'/0'
BIP49 Nested P2WPKH m/49'/1'/0'
BIP84 P2WPKH m/84'/0'/0'
BIP86 P2TR Single-key m/86'/0'/0'

第二种解决方案是将路径信息与恢复码一起备份,明确指出哪些路径与哪些脚本一起使用。我们称之为显式路径。

隐式路径的优点在于用户无需记录他们使用的路径。如果用户将恢复码输入到他们之前使用的相同版本或更高版本的钱包应用程序中,它将自动为之前使用的相同路径重新生成密钥。

隐式脚本的缺点在于其不灵活性。当输入恢复码时,钱包应用程序必须为其支持的每个路径生成密钥,并且必须扫描区块链以查找涉及这些密钥的交易,否则可能找不到所有用户的交易。对于支持许多具有各自路径的功能的钱包来说,这种做法是浪费的,如果用户只尝试了其中的一些功能。

对于不包含版本号的隐式路径恢复码,如BIP39和SLIP39,新版本的钱包应用程序如果不再支持旧路径,在恢复过程中无法警告用户可能无法找到部分资金。反过来,如果用户将恢复码输入到旧软件中,则无法找到用户可能已经收到资金的新路径。包含版本信息的恢复码,如Electrum v2和Aezeed,可以检测到用户输入的是旧版本还是新版本的恢复码,并引导用户到相应的资源。

隐式路径的最终结果是它们只能包含通用的信息(例如标准化路径)或从种子派生的信息(例如密钥)。某些用户特定的重要非确定性信息无法使用恢复码进行恢复。例如,Alice、Bob和Carol收到的资金只能通过其中两个人的签名来花费。尽管Alice只需要Bob或Carol的签名来花费,但她需要他们两个人的公钥才能在区块链上找到他们的共同资金。这意味着他们每个人都必须备份所有三个人的公钥。随着多重签名和其他高级脚本在比特币上变得更加普遍,隐式路径的不灵活性变得更加重要。

显式路径的优点在于它们可以准确描述应该与何种脚本一起使用的密钥。无需支持过时的脚本,也不会出现向后或向前兼容性的问题,而且任何额外的信息(例如其他用户的公钥)都可以直接包含在内。它们的缺点是它们需要用户将额外信息与恢复码一起备份。这些额外的信息通常不会危及用户的安全性,因此不需要像恢复码那样多的保护,尽管它可能会减少用户的隐私,并且需要一些保护。

几乎所有截至目前为止使用显式路径的钱包应用程序都使用了输出脚本描述符标准(简称描述符),该标准在BIP380、BIP381、BIP382、BIP383、BIP384、BIP385、BIP386和BIP389中指定。描述符描述了一个脚本以及与之一起使用的密钥(或密钥路径)。Bitcoin Core文档中的一些示例描述符如下所示(省略部分):

Table 5-3. Bitcoin Core文档中的示例描述符(部分省略)

描述符 解释
pkh(02c6…9ee5) 提供的公钥的P2PKH(支付至公钥哈希)脚本
sh(multi(2,022f… 2a01,03ac…ccbe)) 需要两个签名与这两个密钥相对应的P2SH(支付至脚本哈希)多重签名
pkh([d34db33f/44'/0'/ 0']xpub6ERA…RcEL/1/*) BIP32 d34db33f的扩展公钥(xpub)在路径M/44'/0'/0'上的P2PKH脚本,使用该xpub的M/1/*路径上的密钥

长期以来,专为单签名脚本设计的钱包应用程序倾向于使用隐式路径。而为多重签名或其他高级脚本设计的钱包应用程序则越来越多地采用支持描述符的显式路径。同时支持两种方式的应用程序通常会遵循隐式路径的标准,并提供描述符。

钱包技术栈的详细介绍

简介

现代钱包的开发者可以从各种不同的技术中选择,来帮助用户创建和使用备份,而且每年都会出现新的解决方案。与其详细介绍本章前面描述的每个选项,我们将把重点放在截至2023年初被认为是最广泛使用的技术堆栈上:

  • BIP39恢复代码
  • BIP32 HD密钥派生
  • BIP44风格的隐式路径

所有这些标准早在2014年或之前就已经存在了,你可以轻松找到更多关于它们的使用资源。然而,如果你感到有兴趣,我们鼓励你调查一些可能提供额外功能或安全性的更现代的标准。

BIP39恢复码

BIP39恢复代码是表示(编码)用作种子的随机数的单词序列,用于派生确定性钱包。这个单词序列足以重新创建种子,从而重新创建所有派生密钥。实现了具有BIP39恢复代码的确定性钱包的钱包应用程序在首次创建钱包时会向用户显示一个由12到24个单词组成的序列。这个单词序列是钱包的备份,可以用来在相同或任何兼容的钱包应用程序中恢复和重新创建所有密钥。恢复代码使用户更容易备份,因为它们易于阅读和正确转录。

注意:恢复代码经常与“脑钱包”混淆。它们并不相同。主要区别在于脑钱包由用户选择的单词组成,而恢复代码是由钱包随机创建并呈现给用户的。这个重要区别使得恢复代码更加安全,因为人类是非常不好的随机源。

请注意,BIP39是恢复代码标准的一种实现。BIP39由Trezor硬件钱包背后的公司提出,并与许多其他钱包应用兼容,尽管肯定不是所有钱包都兼容。

BIP39定义了恢复代码和种子的创建过程,我们在这里分成两部分描述,步骤1到6在“生成恢复代码”中展示,步骤7到9在“从恢复代码到种子”中展示。

生成恢复码

恢复代码是由钱包应用程序使用BIP39中定义的标准化流程自动生成的。钱包从熵源开始,添加一个校验和,然后将熵映射到一个单词列表中:

  1. 创建一个128到256位的随机序列(熵)。
  2. 通过取其SHA256哈希的前(熵长度/32)位来创建随机序列的校验和。
  3. 将校验和添加到随机序列的末尾。
  4. 将结果分割成11位长度的段。
  5. 将每个11位值映射到预定义的2,048个单词字典中的一个单词。
  6. 恢复代码是单词序列。

图5-4显示了熵是如何用来生成BIP39恢复代码的。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/5.4.png" alt=""><figcaption><p>图 5-4. 生成熵并将其编码为恢复代码</p></figcaption></figure>

表5-4显示了熵数据的大小与恢复代码长度(以字为单位)之间的关系。

表5-4. BIP39:熵和字长度

熵(比特数) 校验码(比特数) 熵+校验码(比特数) 恢复码单词数
128 4 132 12
160 5 165 15
192 6 198 18
224 7 231 21
256 8 264 24

从恢复码到种子

恢复码代表长度为 128 到 256 位的熵。然后使用熵通过密钥拉伸函数 PBKDF2 派生一个更长的(512 位)种子。生成的种子然后用于构建确定性钱包并派生其密钥。

密钥拉伸函数接受两个参数:熵和盐。盐在密钥拉伸函数中的目的是使构建查找表以进行暴力攻击变得困难。在 BIP39 标准中,盐还有另一个目的——它允许引入一个密码短语,作为额外的安全因素来保护种子,我们将在“BIP39 中的可选密码短语”(第 107 页)中更详细地描述。

注意:密钥拉伸函数,具有 2,048 轮哈希,使使用软件进行暴力攻击恢复码变得稍微困难一些。特殊用途硬件没有受到明显影响。对于需要猜测用户完整恢复码的攻击者来说,代码长度(至少 128 位)提供了足够的安全性。但是对于攻击者可能了解用户代码的一小部分的情况,密钥拉伸通过减慢攻击者检查不同恢复码组合的速度,增加了一些安全性。即使在将近十年前首次发布时,BIP39 的参数也被现代标准认为是脆弱的,尽管这可能是为了与低功耗 CPU 的硬件签名设备兼容而设计的后果。一些替代方案使用更强大的密钥拉伸参数,例如 Aezeed 的 32,768 轮哈希使用更复杂的 Scrypt 算法,尽管它们可能在硬件签名设备上运行时不太方便

步骤7至9描述的过程是从前文“生成恢复代码”中描述的过程继续的:

7. PBKDF2密钥拉伸函数的第一个参数是步骤6生成的熵。

  1. PBKDF2密钥拉伸函数的第二个参数是盐。盐由字符串常量“助记词”与可选的用户提供的密码字符串连接而成。
  2. PBKDF2使用HMAC-SHA512算法对恢复代码和盐参数进行2048轮哈希拉伸,生成一个512位的值作为其最终输出。这个512位的值就是种子。

图5-5展示了如何使用恢复代码生成种子。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/5.5.png" alt=""><figcaption><p>图 5-5. 从恢复码到种子</p></figcaption></figure>

表5-5、5-6和5-7显示了一些恢复代码及其生成的种子的示例。

表5-5. 128位熵BIP39恢复代码,无口令,生成的种子

类型 示例
熵输入(128比特) 0c1e24e5917779d297e14d45f14e1a1a
恢复码(12个单词) army van defense carry jealous true garbage claim echo media make crunch
密码
种子(512比特) 5b56c417303faa3fcba7e57400e120a0ca83ec5a4fc9ffba757fbe63fbd77a89a1a3be4 c67196f57c39a88b76373733891bfaba16ed27a813ceed498804c0570

表 5-6. 128位熵BIP39恢复代码,带有口令,生成的种子

类型 示例
熵输入(128比特) 0c1e24e5917779d297e14d45f14e1a1a
恢复码(12个单词) army van defense carry jealous true garbage claim echo media make crunch
密码 SuperDuperSecret
种子(512比特) 3b5df16df2157104cfdd22830162a5e170c0161653e3afe6c88defeefb0818c793dbb28 ab3ab091897d0715861dc8a18358f80b79d49acf64142ae57037d1d54

表 5-7. 256位熵BIP39恢复代码,无口令,生成的种子

类型 示例
熵输入(256比特) 2041546864449caff939d32d574753fe684d3c947c3346713dd8423e74abcf8c
恢复码(24个单词) cake apple borrow silk endorse fitness top denial coil riot stay wolf luggage oxygen faint major edit measure invite love trap field dilemma oblige
密码
种子(512比特) 3269bce2674acbd188d4f120072b13b088a0ecf87c6e4cae41657a0bb78f5315b33b3 a04356e53d062e55f1e0deaa082df8d487381379df848a6ad7e98798404

需要多少熵?

BIP32允许种子从128位到512位。BIP39接受从128位到256位的熵;Electrum v2接受132位熵;Aezeed接受128位熵;SLIP39接受128位或256位熵。这些数字的变化使得确定安全所需的熵量变得不清晰。我们将尝试澄清这一点。

BIP32扩展私钥由256位密钥和256位链代码组成,总共512位。这意味着最多有2512个不同的可能扩展私钥。如果你的熵超过512位,你仍将获得包含512位熵的扩展私钥,因此即使我们提到的任何标准允许这样做,也没有使用超过512位的必要。

然而,即使有2512个不同的扩展私钥,也只有(稍少于)2256个常规私钥——而实际上正是这些私钥保护了你的比特币。这意味着,如果你的种子使用了超过256位的熵,你仍然会得到仅包含256位熵的私钥。可能会有未来与比特币相关的协议,在这些协议中,扩展密钥中的额外熵提供额外的安全性,但目前并非如此。

比特币公钥的安全强度为128位。使用经典计算机(截至目前,这是唯一可以进行实际攻击的计算机)的攻击者需要对比特币的椭圆曲线执行约2^128次操作,以找到另一个用户的公钥的私钥。128位的安全强度意味着在使用128位熵以上的熵时没有明显的好处(尽管你需要确保你生成的私钥在整个2^256范围内均匀选择)。

更大熵的一个额外好处是:如果攻击者看到了恢复代码的固定百分比(但不是整个代码),那么熵越大,他们就越难以弄清楚他们没有看到的代码的部分。例如,如果攻击者看到了128位代码的一半(64位),则他们可能会能够破解剩余的64位。如果他们看到了256位代码的一半(128位),则他们不太可能能够破解另一半。我们不建议依赖这种防御——要么将你的恢复代码保管得非常安全,要么使用像SLIP39这样的方法,让你将恢复代码分布到多个位置,而不依赖于任何单个代码的安全性。

截至2023年,大多数现代钱包为其恢复代码生成128位熵(或接近128位的值,例如Electrum v2的132位)。

BIP39可选口令

BIP39标准允许在生成种子的派生过程中使用可选的口令。如果没有使用口令,恢复代码将与由常量字符串“mnemonic”组成的盐一起进行拉伸,从而从给定的任何恢复代码生成特定的512位种子。如果使用口令,则拉伸函数将从相同的恢复代码生成不同的种子。事实上,对于单个恢复代码,每个可能的口令都会导致不同的种子。基本上,不存在“错误”的口令。所有口令都是有效的,并且它们都导致不同的种子,形成了一个庞大的可能未初始化的钱包集合。可能的钱包集合如此之大(2^512),以至于没有实际可能性对其进行穷举或意外猜测使用中的钱包。

注意:在BIP39中,不存在“错误”的口令。每个口令都会导致某个钱包,除非该钱包之前已被使用,否则该钱包将为空。

可选的口令创建了两个重要的功能:

  • 第二因素(记忆的东西),使得仅凭恢复码无法单独使用,从而保护恢复码免受随意窃贼的威胁。为了防止技术娴熟的窃贼,你需要使用一个非常强大的口令。
  • 可以提供一种合理的否认或“胁迫钱包”,其中选定的口令导致一个只包含少量资金的钱包,用于转移攻击者对“真实”钱包的注意力,而“真实”钱包包含了大部分资金。

需要注意的是,使用口令也会引入丢失的风险:

  • 如果钱包所有者丧失能力或去世,而没有其他人知道口令,那么种子就无法使用,钱包中存储的所有资金都将永远丢失。
  • 相反,如果所有者将口令备份在与种子相同的地方,那么就失去了第二因素的作用。

虽然口令非常有用,但应仅与备份和恢复的精心计划流程结合使用,考虑到可能存活的所有者并允许其家人恢复加密货币资产的可能性。

从种子创建HD钱包

HD钱包是从单个根种子创建的,该种子是一个128位、256位或512位的随机数。通常情况下,这个种子是通过前面部分详细介绍的恢复码生成或解密的。

HD钱包中的每个密钥都是从这个根种子确定性地派生出来的,这使得在任何兼容的HD钱包中都可以从该种子重新创建整个HD钱包。这使得通过仅转移从根种子派生的恢复码,即可轻松备份、恢复、导出和导入包含数千甚至数百万个密钥的HD钱包。创建HD钱包的主密钥和主链码的过程如图5-6所示。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/5.6.png" alt=""><figcaption><p>图 5-6. 从根种子创建主密钥和链码</p></figcaption></figure>

根种子被输入到HMAC-SHA512算法中,生成的哈希用于创建一个主私钥(m)和一个主链码(c)。

主私钥(m)然后使用正常的椭圆曲线乘法过程 m × G 生成相应的主公钥(M),就像我们在“公钥”中看到的一样。

主链码(c)用于在从父密钥创建子密钥的函数中引入熵,正如我们将在下一节中看到的那样。

子私钥派生

HD钱包使用子密钥派生(CKD)函数从父密钥派生子密钥。

子密钥派生函数基于一种单向哈希函数,结合了:

  • 父私钥或公钥(未压缩密钥)
  • 一个称为链码的种子(256位)
  • 一个索引号(32位)

链码用于在过程中引入确定性随机数据,因此仅知道索引和一个子密钥不足以推导出其他子密钥。仅知道一个子密钥也不足以找到它的兄弟,除非你也有链码。初始链码种子(在树的根部)由种子生成,而后续的子链码从每个父链码派生而来。

这三个项目(父密钥、链码和索引)被组合并进行哈希处理以生成子密钥,具体如下所示。

父公钥、链码和索引号被组合并使用HMAC-SHA512算法进行哈希处理,生成512位哈希。这512位哈希被分成两个256位的半部分。哈希输出的右半部分256位成为子的链码。哈希的左半部分256位被添加到父私钥上,生成子私钥。在图5-7中,我们看到了这个过程的示例,将索引设置为0以生成父的“零”(按索引排序的第一个)子密钥。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/5.7.1.png" alt=""><figcaption><p>图 5-7. 扩展父私钥以创建子私钥</p></figcaption></figure>

更改索引使我们能够扩展父节点并创建序列中的其他子节点(例如,Child 0、Child 1、Child 2 等)。每个父密钥可以拥有 2,147,483,647(2^31)个子节点(2^31 是整个 2^32 范围的一半,因为另一半保留用于我们稍后将在本章中讨论的一种特殊派生类型)。

重复此过程一级下来,每个子节点可以进一步成为一个父节点,并创建自己的子节点,以无限的代数。

使用派生子私钥

子私钥与不确定性(随机)密钥无法区分。 因为派生函数是一个单向函数,所以子密钥不能用于找到父密钥。子密钥也不能用于找到任何兄弟节点。如果你有第 n 个子节点,你无法找到它的兄弟节点,比如第 n-1 个子节点或第 n+1 个子节点,或者序列中的其他任何子节点。只有父密钥和链码才能派生出所有的子节点。如果没有子链码,子密钥也不能用于派生任何孙节点。你需要子私钥和子链码才能启动一个新的分支并派生出孙子节点。

那么子私钥单独能用来做什么呢?它可以用来生成公钥和比特币地址。然后,它可以用来签署交易以花费支付给该地址的任何内容。

注意:子私钥、对应的公钥和比特币地址与随机创建的密钥和地址完全相同。它们属于一个序列的事实在创建它们的 HD 钱包功能之外是不可见的。一旦创建,它们的操作方式与“普通”密钥完全相同。

扩展密钥

正如我们之前所见,密钥派生函数可以根据三个输入在树的任何级别上创建子级,这三个输入是:一个密钥、一个链码和所需子级的索引。这两个基本要素是密钥和链码,它们的组合称为扩展密钥。术语“扩展密钥”也可以被视为“可扩展密钥”,因为这样的密钥可以用来派生子级。

扩展密钥简单地存储和表示为密钥和链码的串联。有两种类型的扩展密钥。扩展私钥是私钥和链码的组合,可用于派生子私钥(以及从中派生的子公钥)。扩展公钥是公钥和链码,可用于创建子公钥(仅公钥),如第59页的“公钥”中描述的。

将扩展密钥视为 HD 钱包树结构中分支的根。有了分支的根,你可以派生出分支的其余部分。扩展私钥可以创建完整的分支,而扩展公钥只能创建公钥分支。

扩展密钥使用 base58check 进行编码,以便在不同的 BIP32 兼容钱包之间轻松导出和导入。扩展密钥的 base58check 编码使用特殊的版本号,在编码为 base58 字符时会生成前缀“xprv”和“xpub”,以使其易于识别。因为扩展密钥包含的字节比常规地址多得多,所以它也比我们之前见过的其他 base58check 编码字符串长得多。

这里是一个扩展私钥的 base58check 编码示例:

xprv9tyUQV64JT5qs3RSTJkXCWKMyUgoQp7F3hA1xzG6ZGu6u6Q9VMNjGr67Lctvy5P8oyaYAL9CA WrUE9i6GoNMKUga5biW6Hx4tws2six3b9c

这是相应的扩展公钥,使用base58check编码:

xpub67xpozcx8pe95XVuZLHXZeG6XWXHpGq6Qv5cmNfi7cS5mtjJ2tgypeQbBs2UAR6KECeeMVKZBP LrtJunSDMstweyLXhRgPxdp14sk9tJPW9

公钥子派生

正如前面提到的,HD钱包的一个非常有用的特性是能够从公钥父级键派生公钥子级键,而无需私钥。这使我们有两种方式来派生子公钥:要么从子私钥,要么直接从父公钥。

因此,扩展公钥可以用来派生该HD钱包结构分支中的所有公钥(仅限公钥)。

这种快捷方式可用于创建仅公钥的部署,其中服务器或应用程序具有扩展公钥的副本,但完全没有私钥。这种部署方式可以产生无限数量的公钥和比特币地址,但不能花费发送到这些地址的任何资金。同时,在另一个更安全的服务器上,扩展私钥可以派生所有相应的私钥来签署交易并花费资金。

这种解决方案的一个常见应用是在提供电子商务应用程序的Web服务器上安装扩展公钥。Web服务器可以使用公钥派生函数为每笔交易(例如,为客户购物车)创建一个新的比特币地址。Web服务器将不具有可能被盗的私钥。没有HD钱包,唯一的方法是在一个单独的安全服务器上生成数千个比特币地址,然后预加载它们到电子商务服务器上。这种方法繁琐,并且需要不断维护,以确保电子商务服务器不会“用完”密钥。

注意间隙

扩展公钥可以生成大约40亿个直接子密钥,远远超过任何商店或应用程序可能需要的数量。然而,一个钱包应用程序要生成所有40亿个密钥并扫描区块链以查找涉及这些密钥的交易,需要的时间是不合理的。因此,大多数钱包一次只生成几个密钥,扫描涉及这些密钥的支付,并在使用之前的密钥时按顺序生成更多的密钥。例如,Alice的钱包生成100个密钥。当它看到对第一个密钥的支付时,它会生成第101个密钥。 有时,一个钱包应用程序会向某人分发一个密钥,后来决定不支付,从而在密钥链中创建一个间隙。只要钱包在间隙之后已经生成了密钥,以便找到后续的支付并继续生成更多的密钥,这是可以接受的。连续未收到支付的最大未使用密钥数量而不会引起问题称为间隙限制。 当一个钱包应用程序已经分发了所有的密钥直到它的间隙限制,而且这些密钥都没有收到支付时,它有三个选项来处理未来请求的新密钥:

  1. 它可以拒绝请求,阻止其接收任何进一步的支付。这显然是一个不受欢迎的选项,尽管它是最简单的实现方式。
  2. 它可以生成超出间隙限制的新密钥。这样确保每个请求支付的人都获得一个唯一的密钥,防止地址重用并提高隐私。然而,如果需要从恢复代码中恢复钱包,或者如果钱包所有者正在使用加载了相同扩展公钥的其他软件,那么这些其他钱包将看不到扩展间隙之后收到的任何支付。
  3. 它可以分发先前分发的密钥,确保平稳恢复,但可能降低钱包所有者和与其交易的人的隐私。

在线商户的开源生产系统,例如BTCPay Server,试图通过使用非常大的间隙限制和限制生成发票的速率来回避这个问题。其他解决方案已经被提出,例如在支付者收到实际交易的新地址之前,要求支付者的钱包构建(但不广播)一笔向可能重用的地址支付的交易。然而,截至目前,这些其他解决方案尚未在生产中使用。

另一个常见的应用是用于冷存储或硬件签名设备。在这种情况下,扩展私钥可以存储在纸钱包或硬件设备上,而扩展公钥可以在线上保存。用户可以随意创建“接收”地址,而私钥则安全地存储在离线状态下。要花费资金,用户可以在离线软件钱包应用程序或硬件签名设备上使用扩展私钥。图5-8说明了将父公钥扩展以派生子公钥的机制。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/5.8.png" alt=""><figcaption><p>图 5-8. 扩展父公钥以创建子公钥</p></figcaption></figure>

在网络商店使用扩展公钥

让我们通过看看加布里埃尔的网络商店来了解HD钱包是如何使用的。

加布里埃尔最初是抱着兴趣的心态建立了他的网络商店,基于一个简单的托管的WordPress页面。他的商店非常基础,只有几个页面和一个带有单一比特币地址的订单表单。

加布里埃尔使用他的常规钱包生成的第一个比特币地址作为他的商店的主要比特币地址。顾客会使用表单提交订单并向加布里埃尔发布的比特币地址付款,触发一封包含订单详情的电子邮件,供加布里埃尔处理。尽管每周只有几个订单,但这个系统足够满足需求,尽管它削弱了加布里埃尔、他的客户和他支付的人的隐私。

然而,这个小型网络商店变得相当成功,吸引了很多来自当地社区的订单。很快,加布里埃尔就不堪重负。由于所有订单支付同一个地址,因此在正确匹配订单和交易时变得困难,特别是当相同金额的多个订单相继而来时。

典型比特币交易接收者选择的唯一元数据是金额和付款地址。没有主题或消息字段可用于保存唯一标识发票号。

通过HD钱包,加布里埃尔的问题得到了更好的解决方案,因为他可以在不知道私钥的情况下生成公共子密钥。加布里埃尔可以在他的网站上加载一个扩展公钥(xpub),用于为每个客户订单派生一个唯一地址。这个唯一地址立即提高了隐私,还为每个订单提供了一个可以用于跟踪已支付发票的唯一标识。

使用HD钱包允许加布里埃尔从他的个人钱包应用程序中支出资金,但加载在网站上的xpub只能生成地址并接收资金。这是HD钱包的一个很好的安全功能。加布里埃尔的网站不包含任何私钥,因此对其的任何黑客攻击都只能窃取加布里埃尔未来可能收到的资金,而不是他过去收到的任何资金。

为了从他的Trezor硬件签名设备中导出xpub,加布里埃尔使用基于Web的Trezor钱包应用程序。要导出公钥,Trezor设备必须插入。请注意,大多数硬件签名设备永远不会导出私钥——它们始终保留在设备上。

加布里埃尔将xpub复制到他的网店的比特币支付处理软件中,比如广泛使用的开源BTCPay服务器。

强化子密钥衍生

从xpub推导出公钥分支的能力非常有用,但也带来了潜在的风险。访问xpub并不会给予对子私钥的访问权限。然而,因为xpub包含了链代码,如果某个子私钥已知或某种方式泄露,它可以与链代码一起用于推导出所有其他子私钥。一个泄露的子私钥,加上父链代码,会暴露出所有子节点的私钥。更糟糕的是,子私钥与父链代码一起可以用于推断出父私钥。

为了应对这种风险,HD钱包提供了一种另类的衍生函数,称为硬化衍生,它打破了父公钥与子链代码之间的关系。硬化衍生函数使用父私钥来推导子链代码,而不是使用父公钥。这在父子序列中创建了一个“防火墙”,其链代码不能用于危及父或同级私钥。硬化衍生函数看起来几乎与普通的子私钥衍生相同,只是父私钥被用作哈希函数的输入,而不是父公钥,如图5-9中的图表所示。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/5.9.png" alt=""><figcaption><p>图 5-9. 子密钥的硬化衍生;省略了父公钥。</p></figcaption></figure>

当使用硬化私有派生函数时,得到的子私钥和链码与使用常规派生函数得到的完全不同。结果的“分支”密钥可以用来生成扩展公钥,因为它们包含的链码不能被利用来揭示它们的兄弟或父母的任何私钥。因此,硬化派生用于在扩展公钥使用的级别上创建“间隙”。

简而言之,如果你想要使用xpub方便地派生公钥分支,而又不暴露于泄漏链码的风险之中,那么你应该从硬化父节点派生它,而不是从普通父节点派生。作为最佳实践,主密钥的一级子代始终通过硬化派生来派生,以防止主密钥被破坏。

普通和强化衍生的索引号

派生函数中使用的索引号是一个32位整数。为了区分通过常规派生函数创建的密钥和通过硬化派生创建的密钥,该索引号被分为两个范围。

索引号介于0和2^31-1(0x0到0x7FFFFFFF)之间,仅用于常规派生。索引号介于2^31和2^32-1(0x80000000到0xFFFFFFFF)之间,仅用于硬化派生。因此,如果索引号小于2^31,则子代是常规的,而如果索引号等于或大于2^31,则子代是硬化的。

为了使索引号更易于阅读和显示,硬化子代的索引号从零开始显示,但带有一个质数符号。因此,第一个常规子代密钥显示为0,而第一个硬化子代(索引0x80000000)显示为0'。然后,在序列中,第二个硬化密钥的索引将为0x80000001,并显示为1',依此类推。当你看到HD钱包索引i'时,意味着2^31+i。在常规ASCII文本中,质数符号被替换为单引号或字母h。对于可能在shell或其他上下文中使用文本的情况(其中单引号具有特殊含义),建议使用字母h。

HD钱包密钥标志符(路径)

HD钱包中的密钥使用“路径”命名约定来标识,树的每个级别之间用斜杠(/)字符分隔(见表5-8)。从主私钥派生的私钥以“m.”开头。从主公钥派生的公钥以“M.”开头。因此,主私钥的第一个子私钥是m/0。第一个子公钥是M/0。第一个子代的第二个孙子是m/0/1,依此类推。

密钥的“祖先”从右向左读取,直到达到派生它的主密钥为止。例如,标识符m/x/y/z描述的是密钥m/x/y的第z个子代,它是密钥m/x/y的第y个子代,它是密钥m/x的第x个子代,它是m的子代。

表 5-8. 以下是 HD 钱包路径的一些示例

HD路径 私钥描述
m/0 The first (0) child private key from the master private key (m)
m/0/0 The first grandchild private key from the first child (m/0)
m/0'/0 The first normal grandchild private key from the firsthardened child (m/0')
m/1/0 The first grandchild private key from the second child (m/1)
M/23/17/0/0 The first great-great-grandchild public key from the first great-grandchild from the 18th grandchild from the 24th child

HD钱包树状结构导航

在 HD 钱包树结构中导航提供了巨大的灵活性。每个父扩展密钥可以有 40 亿个子级:20 亿个普通子级和 20 亿个硬化子级。每个子级都可以有另外 40 亿个子级,依此类推。树的深度可以任意,有无限的代数。然而,尽管有如此大的灵活性,但在这个无限树中导航变得非常困难。将 HD 钱包在实现之间转移尤其困难,因为将其内部组织成分支和子分支的可能性是无穷无尽的。

两个 BIP 提出了这种复杂性的解决方案,通过创建一些关于 HD 钱包树结构的标准提出了解决方案。BIP43 提议使用第一个硬化子级索引作为特殊标识符,表示树结构的“目的”。根据 BIP43,HD 钱包应该只使用树的一级分支,通过定义其目的来使用索引号来识别树的其余部分的结构和命名空间。例如,只使用分支 m/i' 的 HD 钱包旨在表示特定目的,并且该目的由索引号 “i” 来标识。

在此规范的基础上,BIP44 提议作为 BIP43 下的 “目的” 编号 44' 的多账户结构。遵循 BIP44 结构的所有 HD 钱包都被识别为它们只使用树的一个分支:m/44'。

BIP44 指定了结构,由五个预定义的树级别组成:

m / purpose' / coin_type' / account' / change / address_index

第一级 “purpose” 总是设为 44'。第二级 “coin_type” 指定了加密货币币种的类型,允许创建多币种 HD 钱包,其中每种币种都有自己的子树位于第二级之下。比特币为 m/44'/0',比特币测试网为 m/44'/1'。

树的第三级是 “account”,它允许用户将他们的钱包细分为不同的逻辑子账户,用于会计或组织目的。例如,一个 HD 钱包可能包含两个比特币 “账户”:m/44'/0'/0' 和 m/44'/0'/1'。每个账户都是其自己子树的根。

在第四级 “change” 上,HD 钱包有两个子树,一个用于创建接收地址,另一个用于创建找零地址。需要注意的是,前面的级别使用了硬化派生,而这一级别使用了普通派生。这是为了允许这一级别的树导出扩展公钥供非安全环境使用。 可用地址由 HD 钱包作为第四级的子代派生,使得树的第五级成为 “address_index”。例如,主帐户中用于付款的第三个接收地址将是 M/44'/0'/0'/0/2。下表显示了一些更多的示例。

Table 5-9. BIP44 HD 钱包结构示例

HD 钱包路径 描述
m/44'/0'/0'/0/2 主比特币账户的第三个接收公钥
M/44'/0'/3'/1/14 第四个比特币账户的第十五个找零地址公钥
m/44'/2'/0'/0/1 Litecoin主账户的第二个私钥,用于签署交易

许多人关注保护比特币免受盗窃和其他攻击,但丢失比特币的主要原因之一,也许是主要原因之一,是数据丢失。如果丢失了用于花费比特币的密钥和其他必要数据,那么这些比特币将永远无法花费。没有人可以为你取回它们。在本章中,我们看了现代钱包应用程序使用的系统,帮助你防止丢失这些数据。然而,请记住,实际上要使用可用的系统来制作好的备份并定期测试它们是由你来决定的。

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

0 条评论

请先 登录 后评论