汇总我们每周系列文章的所有已发布部分,内容涉及在区块高度 709,632 激活 Taproot 的准备工作。

  1. Bech32m 发送支持
  2. Taproot 对单签名是否有意义?
  3. Taproot 描述符
  4. 从 P2WPKH 到单签 P2TR
  5. 我们为什么要等待?
  6. 通过使用学习 Taproot
  7. 多签
    1. 使用多签
    2. 阈值签名
  8. 多签随机数
  9. 签名适配器
    1. 适配器签名的魔法
    2. 多签适配器
  10. PTLCs
    1. HTLC 的隐私问题
    2. PTLC 解决方案
  11. 使用 Taproot 的闪电网络
    1. 闪电网络上的 PTLCs
    2. P2TR 通道
    3. 时间预估
  12. 使用 Taproot 的保险库
  13. 备份与安全方案
  14. 在 Signet 上测试
  15. 仍需 Signmessage 协议
  16. 输出关联
  17. 合作永远是可行选项吗?
  18. 琐事
  19. 未来的共识变化
  20. 激活时会发生什么?
  21. 感谢!

Bech32m 发送支持

最初发表于 Newsletter #154

从预计在 11 月到来的区块高度 709,632 开始,比特币用户将能够安全地接收发送到 taproot 地址的付款。考虑到用户对 taproot 的期待,以及钱包开发者有 5 个月的时间来实现对 taproot 的支持,Optech 预计到时会有数个流行的钱包允许用户在第一时间生成 taproot 地址。

这意味着任何会向用户提供的地址发送比特币的钱包或服务,都需要在区块高度 709,632 前支持发送至 taproot 地址,否则可能会让用户感到困惑并失望。Pay to TapRoot(P2TR)地址使用了 bech32m(参见 BIP350),它与 BIP173 用于 segwit v0 P2WPKH 和 P2WSH 地址的 bech32 算法略有不同。bech32m 在校验和函数中使用 0x2bc830a3 常量,而传统 bech32 则使用 0x01

只需改变这一常量即可为校验 bech32m 校验和提供支持,但在处理现有 P2WPKH 和 P2WSH 地址时仍要使用原始常量。也就是说,代码需要先在不验证校验和的情况下解析地址,判断它是 v0 segwit(bech32)还是 v1+ segwit(bech32m),然后再使用对应的常量来验证校验和。更多示例可参考 bech32#56,它更新了 C、C++、JS 和 Python 的 bech32 参考实现。如果代码已经使用了参考库,可以更新至该仓库的最新版本,但要注意其中部分 API 发生了小幅更改。BIP350 和参考实现提供的测试向量,所有 bech32m 实现都应当进行使用以验证正确性。

虽然在区块高度 709,632 之前向 taproot 地址接收付款并不安全,但向这些地址发送付款对于付款方而言并不会造成任何问题。自 Bitcoin Core 0.19(2019 年 11 月发布)起,Bitcoin Core 就开始支持传播和挖矿包含 taproot 输出的交易。Optech 鼓励各钱包和服务的开发者现在就着手实现对 bech32m taproot 地址付款的支持,而不要等到 taproot 激活后再做准备。

Taproot 对单签名是否有意义?

最初发表于 Newsletter #155

使用 Optech 的 交易大小计算器,我们可以比较不同类型单签名交易的大小。正如预期,使用 P2WPKH 输入和输出的交易远小于使用 P2PKH 输入和输出的交易——但或许令人惊讶的是,P2TR 交易比同等的 P2WPKH 交易略大。

  P2PKH (legacy) P2WPKH (segwit v0) P2TR (taproot/segwit v1)
Output 34 31 43
Input 148 68 57.5
2-in, 2-out tx 374 208.5 211.5

这可能会让人觉得,为了迎接在区块 709,632 激活的 taproot 而在单签名钱包中实现 taproot 花费是得不偿失的,但当我们进一步研究时会发现,对于钱包用户和整个网络而言,使用 P2TR 进行单签名仍然有许多好处。

  • 花费更便宜: 与花费 P2WPKH UTXO 相比,花费单签名 P2TR UTXO 在输入层面上节约了大约 15% 的成本。上表这样过于简单的分析掩盖了一个细节,即花费者无法选择他们被要求支付的地址,所以如果你还停留在 P2WPKH,而其他人都升级到了 P2TR,那么你的 2 入、2 出交易的实际常见大小将会达到 232.5 vbytes——而全部使用 P2TR 的交易仍然只有 211.5 vbytes。

  • 隐私: 虽然当早期采用者切换到新的脚本格式时会失去一些隐私,但用户切换到 taproot 也能立刻获得隐私增强。你的交易在链上可能与正在使用新 LN 通道、更高效的 DLCs、安全的多签、各种巧妙的钱包备份恢复方案或其他上百种全新发展场景的人看起来毫无区别。

    现在就对单签名采用 P2TR 还能让你的钱包在之后升级到多签名、tapscript、LN 支持或其他功能时,不会影响你的现有用户的隐私。UTXO 是在你旧版或新版软件中接收的都无关紧要——这两种 UTXO 在链上看起来没有差别。

  • 更方便硬件签名设备: 自从重新发现了手续费超额支付攻击以来,一些硬件签名设备在没有为该交易输入的每个 UTXO 提供元数据(包含创建该 UTXO 的完整交易中重要部分的副本)的情况下,拒绝为交易签名。这样会极大增加硬件签名器需要执行的最糟糕情况处理量,对主要通过尺寸有限的二维码进行交互的硬件签名器来说尤其棘手。taproot 消除了导致手续费超额支付攻击的漏洞,从而能够显著提高硬件签名器的性能。

  • 更可预测的费率: 适用于 P2PKH 和 P2WPKH UTXO 的 ECDSA 签名大小具有灵活性(参见 Newsletter #3)。由于钱包需要在创建签名前先决定交易的费率,大多数钱包只是默认假设最糟糕的签名大小,并接受在实际生成更小签名时稍微超额支付费率。对于 P2TR,则可以预先明确签名的确切大小,钱包就能可靠地选择精准的费率。

  • 帮助全节点: 比特币系统的整体安全性依赖于有相当比例的比特币用户使用自己的节点验证所有已确认的交易,包括验证你的钱包所创建的交易。taproot 的 schnorr 签名可以被高效地批量验证,在节点赶上之前区块的过程中,CPU 耗时大约可以减少一半。即使你对上面提到的其他优势都不感兴趣,也可以考虑为了那些运行全节点的人而做好使用 taproot 的准备。

Taproot 描述符

最初发表于 Newsletter #156

输出脚本描述符 为钱包提供了一种通用方式,用来存储生成地址所需的信息、有效扫描付款给这些地址的输出,以及之后从这些地址花费。此外,描述符相对紧凑且包含一个基础校验和,这使其在备份地址信息、在不同钱包之间复制或在合作提供多签的多个钱包之间共享时都非常方便。

尽管当前只有少数项目在使用描述符,但它们和相关的 miniscript 项目有潜力显著提升不同钱包和工具之间的互操作性。随着越来越多的用户利用 taproot 带来的好处,通过多签来加强安全性,以及通过备份花费条件来提高恢复能力,这一点将变得愈加重要。

在此之前,需要先对描述符进行更新以适配 taproot。最近合并的 Bitcoin Core #22051 拉取请求正是针对这一需求。该语法设计允许使用单一描述符模板,同时提供使用 P2TR 密钥路径花费和脚本路径花费所需的全部信息。对于简单的单签名,以下描述符就足够了:

tr(<key>)

相同的语法也适用于多签和阈值签名。例如,Alice、Bob 和 Carol 使用 MuSig 聚合它们的密钥,然后支付给 tr(<combined_key>)

出人意料的是,“tr(<key>) 中的 key” 并不会直接是地址中所编码的那个密钥。tr() 描述符遵循了 BIP341 中的安全性建议,使用一个承诺于不可花费脚本树的内部密钥,这就消除了对简单密钥聚合方案(像 MuSig 和 MuSig2 这类更先进的方案不受影响)的一个攻击。

对于脚本路径花费,新增了一种可指定二叉树内容的语法。例如,{ {B,C} , {D,E} } 描述了这样一棵树:

Internal key
    / \
   /   \
  / \ / \
  B C D E

可以将这棵树作为可选的第二个参数传入之前使用的描述符模板。例如,如果 Alice 希望能够通过密钥路径花费,但也允许 Bob、Carol、Dan 和 Edmond 以能够为她生成审计轨迹的脚本路径花费(但不对第三方链上监控暴露),她可以使用如下描述符:

tr( <a_key> , { {pk(<b_key>),pk(<c_key>)} , {pk(<d_key>),pk(<e_key>)} )

上述功能足以让描述符用于 taproot,但拉取请求 #22051 中提到仍有一些可能被添加的功能,用于让描述符更好地完整描述预期的策略:

  • *无效化密钥路径: 某些用户可能希望禁止通过密钥路径花费,从而强制使用脚本路径花费。现在可以在 tr() 第一个参数中使用不可花费的密钥来实现,但能够在描述符本身中记录这一偏好并让它计算出一个保护隐私的不可花费密钥路径将更好。

  • *Tapscript 多签: 对于传统和 v0 segwit,multi()sortedmulti() 描述符支持 OP_CHECKMULTISIG 操作码。为了在 taproot 中实现批量验证,基于脚本的多签在 tapscript 中的处理方式有所不同,因此 tr() 描述符目前需要通过 raw() 脚本来指定任何必需的多签操作码。对 tapscript 版本的 multi()sortedmulti() 进行更新将非常有用。

  • *基于 MuSig 的多签: 在本文前面,我们描述了 Alice、Bob 和 Carol 手动聚合它们的密钥,以使用一个 tr() 描述符。理想情况下,应当能有一个函数允许像 tr(musig(<a_key>, <b_key>, <c_key>)) 这样指定,这样他们就能保留全部初始密钥信息并用它来填充它们协同签名所用 PSBT 中的各字段。

  • *时间锁、哈希锁和点锁: 这些在闪电网络、DLCscoinswaps 以及许多其他协议中使用的强大结构,目前只能通过 raw() 函数来描述。可将它们直接加入描述符是可行的,但也可能会在描述符的姊妹项目 miniscript 中添加对它们的支持。miniscript 整合到 Bitcoin Core 仍在进行中,但我们预期它的创新将和 PSBT、描述符等工具一样,推广到其他钱包中。

钱包并不需要实现描述符就能开始使用 taproot,但那些实现了描述符的,将为自己使用更高级的 taproot 功能奠定更好的基础。

从 P2WPKH 到单签 P2TR

最初发表于 Newsletter #157

对于已经支持接收和使用 v0 segwit P2WPKH 输出的钱包来说,将其升级到用于单签的 v1 segwit P2TR 应该相对容易。以下是主要步骤:

  • 使用新的 BIP32 密钥推导路径: 你不需要修改你的 BIP32 分层确定性 (HD) 代码,并且你的用户也不需要更换种子。1 然而,我们强烈建议你为你的 P2TR 公钥使用新的推导路径(例如由 BIP86 定义);如果你不这样做,当你在 ECDSA 和 schnorr 签名两者中都使用相同密钥时,可能会导致潜在攻击

  • 通过其哈希值调整你的公钥: 尽管在单签场景中技术上并非必须,尤其当你的所有密钥都来自随机选定的 BIP32 种子时,BIP341 建议让你的密钥承诺到一个不可花费的脚本哈希树中。其操作很简单,只需要使用椭圆曲线加法操作,将你的公钥与该公钥哈希得到的曲线点相加即可。遵循这一建议的好处在于,如果你日后添加无脚本的多签支持,或者为 tr() 描述符添加支持,你也可以使用相同的代码。

  • 创建你的地址并进行监控: 使用 bech32m 来创建你的地址。付款将发送到脚本 OP_1 <tweaked_pubkey>。你可以使用与扫描 v0 segwit 地址(如 P2WPKH)相同的方法来扫描支付到该脚本的交易。

  • 创建支出交易: 对于 taproot 来说,所有的非见证字段都与 P2WPKH 相同,因此你无需担心交易序列化的改变。

  • 创建签名消息: 这是对支出交易数据的承诺。大部分数据与为 P2WPKH 交易所签名的内容相同,但字段的顺序已改变,并且有一些额外内容需要签名。实现这一点只需要对各种数据进行序列化和哈希处理,所以编写这部分代码应该相对容易。

  • 对签名消息的哈希进行签名: 生成 schnorr 签名有多种方法。最好的方式是不“自己动手写加密”而是使用你信任的、经过充分审阅的库提供的函数。但如果因某些原因你无法这样做,BIP340 提供了一种算法,如果你已经有可用于制作 ECDSA 签名的原语,那么实现它应该相当简单。当你获得签名后,将其放入输入的见证数据中,然后发送你的支出交易。

即使在 taproot 于区块 709,632 激活之前,你也可以使用 testnet、公用默认 signet 或者 Bitcoin Core 的私有 regtest 模式来测试你的代码。如果你为开源钱包添加了 taproot 支持,我们鼓励你将实现它的拉取请求链接添加到 Bitcoin Wiki 上的 taproot 用法bech32m 采用页面,以便其他开发者可以从你的代码中学习。

我们为什么要等待?

最初发表于 Newsletter #158

本系列之前的文章鼓励钱包和服务开发者立即开始实施 Taproot 升级,以便在 Taproot 激活时准备就绪。但我们也警告不要在区块 709,632 前生成任何 P2TR 地址,否则可能导致服务或用户资金损失。

不建议提前生成地址的原因是,在区块 709,632 之前,任何发送至 P2TR 式输出的资金均可被任何人花费。这些资金将完全无安全保障。但从该区块开始,数千个全节点将开始强制执行 BIP341BIP342(以及关联的 BIP340)的规则。

如果区块链重组能被完全排除,那么在看到最后一个 Taproot 前区块(区块 709,631)后立即生成 P2TR 地址是安全的。但存在对区块链重组的担忧——不仅是意外重组,还包括蓄意制造以窃取早期 P2TR 支付的资金。

设想大量用户希望成为首批接收 P2TR 支付的人。他们在看到区块 709,631 后立即天真地向自己发送资金。2 这些资金在区块 709,632 中是安全的,但可能被创建替代 709,631 区块的矿工窃取。如果发送至 P2TR 输出的资金价值足够大,尝试挖两个区块而非一个可能变得更为有利可图(详见手续费狙击主题)。

因此,在重组风险有效消除前,我们不建议软件或服务生成 P2TR 地址。我们认为等待激活后 144 个区块(约一天)是较为保守的安全边际,可在最小化风险的同时避免显著延迟用户享受 Taproot 优势。

简言之:

  • 709,631: 最后一个允许任何人花费 P2TR 式输出资金的区块
  • 709,632: 首个要求 P2TR 输出必须满足 BIP341BIP342 规则才能被花费的区块
  • 709,776: 钱包可开始为用户提供 P2TR 输出的 Bech32m 接收地址的合理区块

以上均不影响本系列首篇文章的建议——应尽快支持向 Bech32m 地址付款。若有人在您认为安全前请求向 P2TR 地址付款,风险由其自行承担。

通过使用学习 Taproot

最初发表于 Newsletter #159

将近两年前,James Chiang 和 Elichai Turkel 创建了一个开源仓库,其中包含一系列 Jupyter 笔记本,旨在为 Optech 组织的开发者培训提供 Taproot 技术相关内容。在旧金山、纽约和伦敦举办的研讨会收到了积极的反馈,但由于旅行限制,后续的线下研讨会未能如期进行。

自 Jupyter 笔记本发布以来,Taproot 发生了多项变更。然而,Taproot 支持已合并到 Bitcoin Core,这使得这些笔记本可以不再依赖于 Bitcoin Core 的自定义分支。开发者 Elle Mouton 友善地更新了这些笔记本,使其适应所有的更改,使其再次成为快速掌握 Taproot 算法和数据类型的绝佳实践工具。

这些笔记本分为四个部分:

  • 第 0 部分 包含一个帮助您设置环境的笔记本,涵盖椭圆曲线密码学的基础知识,并介绍 BIPs 340341342 中广泛使用的标签哈希。

  • 第 1 部分 指导您创建 Schnorr 签名。掌握这些知识后,您将学习如何使用 MuSig 协议创建多重签名

  • 第 2 部分 带您全面了解 Taproot。首先回顾 Segwit v0 交易的基本原理,然后帮助您创建和发送 Segwit v1(Taproot)交易。在掌握第 1 部分知识后,您将学习如何使用 MuSig 创建并花费 Taproot 输出。随后,您将接触密钥调整(key tweaking)概念,并学习如何利用 Taproot 公钥承载数据承诺。掌握承诺创建后,您将了解 Tapscript——其与传统及 Segwit v0 脚本的区别,以及如何创建 Tapscript 树的承诺。最后,一个简短的笔记本将介绍如何使用 Huffman 编码来创建最优的脚本树。

  • 第 3 部分 提供了一个可选练习,内容是创建一个 Taproot 输出,该输出会随着未花费时间的增加而改变所需的签名数量——在正常情况下提供高效的花费方式,同时在出现问题时提供强大的备份方案。

这些笔记本包含众多相对简单的编程练习,确保您真正掌握所学内容。本专栏作者并非优秀的程序员,但能够在六小时内完成所有笔记本练习,并遗憾没有更早学习这些内容。

多签

最初发表于 Newsletter #160

在撰写本文之前的 1,000 个区块中,11% 的交易输入包含了多签操作码。如果许多创建这些交易的用户和服务将多签操作码切换为无脚本的多签,Taproot 的两个最大和最直接的好处将会显现。

第一个主要好处是交易大小的减少。基于脚本的多签随着更多密钥和签名的需求而增大,但多签则保持为一个恒定的小尺寸。最小的有效多签策略(1-对-2)所需的空间比一个可以涉及成千上万签署者的多签策略还要大。尺寸的减少直接导致了多签用户的手续费减少,同时也间接减少了所有用户的手续费,因为相同数量的已确认交易需求可以通过更小的区块空间得到满足。

展示多签与多签操作码节省的图表

第二个主要好处是隐私的提高。每次使用多签的交易都会在区块链上有明显的记录,观察者可以通过这些记录推测出个别用户的钱包历史和当前余额。例如,在区块 692,039 中,我们不仅可以区分多签交易和单签名交易,还可以区分不同的签名集合大小和多签的阈值。

展示当前区块中见证不可替代性的插图

相比之下,第三方仅查看区块链数据时,无法知道支出者是否使用了多签。当多签用于密钥路径支出时,它与单签名支出无法区分。如果上述区块中的所有单签名和多签都切换为 P2TR 密钥路径支出,只有少数特殊的支出会因其脚本而被区分出来(即便是这些支出,也可能在最好的情况下使用密钥路径支出)。

展示理想情况下可替代的见证如何呈现的插图

使用多签

我们知道有三种专为比特币设计的基于 Schnorr 的多签方案,它们都是 MuSig 系列的一部分:

  • MuSig(也称为 MuSig1),实现起来相对简单,但在签名过程中需要三轮通信。

  • MuSig2,同样实现起来较为简单。它消除了一个通信轮次,并将另一个通信轮次与密钥交换结合。这样可以使用与当前基于脚本的多签类似的签名过程。这确实需要存储额外数据,并且非常小心,确保你的签名软件或硬件不会被误导重复进行某部分签名会话。我们将在下周的 为 Taproot 做准备 栏目中更详细地探讨这种权衡。

  • MuSig-DN(确定性随机数),实现起来复杂得多。参与者之间的通信无法与密钥交换结合,但它的优势在于不会受到重复会话攻击的影响。

所有签名者必须就使用哪种协议达成一致,因此可能会出现网络效应,许多实现选择使用相同的协议。MuSig 提案的作者 建议 由于其相对简单性和高效性,MuSig2 将成为大多数实现的选择。

目前有一个开放的并正在积极开发的 PR,用于向 libsecp256k1-zkp 项目添加 MuSig2 支持。我们预计大多数软件的基本多签工作流将如下所示:

  1. 每个参与者的钱包生成一个 BIP32 xpub,并通过输出脚本描述符或其他方式与所有其他参与者共享(这与当前多签使用的方式相同)。

  2. 任何一个钱包都可以通过将其在某个 BIP32 深度上的公钥与所有其他钱包在同一深度的公钥相结合,生成一个聚合公钥。这个聚合公钥可以用于接收 P2TR 支付。

  3. 当其中一个钱包想要支出资金时,它使用基于 PSBT 的工作流,类似于当前使用基于脚本的多签的流程,但现在需要签署者之间进行两轮通信。在第一轮中,提议者创建未签名交易并包含一对随机生成的随机数。必须确保随机数的生成不是完全确定性的,以避免为不同的签名使用相同的随机数。提议者将包含随机数的 PSBT 发送给其他钱包。

  4. 其他钱包接收 PSBT 并更新其中的随机数,然后将更新后的 PSBT 发送给其他钱包,或发送给为钱包提供信任的协调员。

  5. 当所有钱包都获得所有随机数对后,它们将它们合并为一个单一的随机数。协调员也可以为它们执行此操作。然后,所有钱包更新它们的 PSBT 版本并添加各自的部分签名,将 PSBT 发送给其他钱包或协调员。最后,所有部分签名将合并生成最终签名,并将交易广播。

阈值签名

仅凭 MuSig 系列的多签方案,你只能实现 n 对 n 的签名——每个贡献密钥的参与者必须也贡献一个部分签名以形成最终签名。这在一些当前使用的基于脚本的多签用例中运行良好,例如支出 2-对-2 的闪电网络资金输出,但它与其他流行的策略有所不同,例如许多交易所使用的 2-对-3 多签脚本。

目前,几位开发者正在研究阈值签名方案,它将为 k-对-n 场景带来与多签相同的效率和隐私好处,但在这些方案可用之前,有一个简单的技巧可以使用。

在许多阈值情况下,事先知道哪些参与者最有可能签名。例如,在一个 2-对-3 的场景中,可能已经知道通常 Alice 和 Bob 会共同签名,而 Carol 只有在其他两人都无法签名时才会签名。对于这种情况,主密钥可以使用多签进行 Taproot 密钥路径支出(例如 Alice 和 Bob 之间),而额外的结果(如 Alice 和 Carol,或 Bob 和 Carol)可以使用 OP_CHECKSIG 操作码在 tapscripts 的树状结构中单独分支。

在正常情况下,以上方案与单签名或多签交易具有相同的效率和隐私。在异常情况下,支出仍然按预期工作,并且比在链上发布多签参数更高效和隐私。

尽管希望最小化费用并实现最大隐私的用户最终可能会切换到纯阈值签名方案,但上述方案可能仍会继续使用,因为它为审计员(如果他们知道所有参与者的公钥)提供了关于哪些相应的私钥被用来签名的链上证明。

编辑:关于 MuSig2 的部分文字已更新,以澄清在预共享随机数时需要格外小心,因此预计大多数使用 MuSig2 的常规钱包将在需要时生成新的随机数。我们感谢 #secp256k1 IRC 频道成员分享他们的担忧。

多签随机数

最初发表于 Newsletter #161

在上周的专栏中,我们讨论了多签并通过 MuSig2 举例进行说明。我们所做的描述在技术上是正确的,但有几位参与 MuSig2 的密码学家担心我们建议的使用方法是危险的。我们更新了我们的描述,以解决他们的直接担忧,并开始更深入地研究这一问题。在本文中,我们将探讨我们所学到的,可能是安全实施多重签名的最大挑战:避免重用 nonce。

为了验证比特币中的签名,您需要通过签名、签名的消息(例如交易)、您的公钥和公有 nonce 来填充一个公开已知的方程式。只有在您知道私钥和私有nonce的情况下,才能平衡这个方程式。因此,任何看到该方程式的人都可以认为这个消息和公钥的签名是有效的。

将签名和消息包括在方程式中的动机是显而易见的。公钥是私钥的代替,那么公有 nonce 的作用是什么呢?如果它不存在,方程式中除了您的私钥以外的所有值都是已知的,这意味着我们可以使用基础代数来求解唯一的未知值。但代数无法求解两个未知数,因此 nonce 的私有形式能够保持您的私钥的秘密。正如公钥在签名方程式中是私钥的代替一样,nonce 的公有形式则代替其私有形式。

在这个背景下,nonce 不仅是一次性使用的数字,而且必须仅使用一次。如果您使用相同的 nonce 进行两次不同的签名,那么这两个签名方程式可以合并,nonce 可以被消除,从而有人可以解决唯一剩下的未知数——您的私钥。如果您使用BIP32 标准派生(非硬化派生),这可能是几乎所有多重签名钱包都会使用的方式,那么一旦暴露一个私钥,就意味着该BIP32路径下的所有其他私钥都会被暴露(甚至可能在其他路径中也是如此)。这意味着一个已经收到了比特币的多重签名钱包,如果其中一个签名者重用了一个 nonce,那么该签名者在这个钱包下的所有地址都会被泄露。

单签名钱包,或者使用基于脚本的多重签名的钱包,可以通过一个简单的技巧来避免重用 nonce:他们使得 nonce 依赖于他们签署的消息。如果消息发生任何变化,nonce 也会变化,因此它们不会重用 nonce。

但多重签名不能使用这个技巧。它们要求每个共同签名者不仅贡献一个部分签名,还要贡献一个部分公有 nonce。多个部分公有 nonce 被组合起来生成一个聚合公有 nonce,该 nonce 将与签名的消息一起使用。

这意味着,即使交易保持不变,也不应该多次使用相同的部分 nonce。如果第二次签署时,某个共同签名者改变了他们的部分 nonce(改变了聚合 nonce),您的第二个部分签名实际上就是为一个不同的消息签署的,这会暴露您的私钥。由于对于每个参与方来说,让他们的私有 nonce 依赖于所有其他方的部分公有 nonce 是完全不可能的,因此在多重签名中没有简单的方法来避免nonce重用。

乍一看,这似乎不是一个大问题。只需要让签名者每次签署时生成一个新的随机 nonce。实现起来比听起来要难得多——自 2012 年以来,人们一直在发现依赖生成随机 nonce 的钱包中的比特币丢失漏洞。

但即便钱包能够生成高质量的随机 nonce,它仍然需要确保每个 nonce 只使用一次。这是一个真正的挑战。在我们上周专栏的原始版本中,我们描述了一个MuSig2兼容的冷钱包或硬件签名设备,它会在首次运行时生成大量的 nonce。然后,钱包或设备需要确保每个nonce 从未与多个部分签名一起使用。虽然这听起来简单——每次使用 nonce 时递增计数器——但当软件和硬件可能因偶然原因出现故障,或者受到外部甚至恶意干预时,这可能会变得非常复杂。

也许钱包减少 nonce 重用风险的最简单方法是尽可能缩短 nonce 的存储时间。我们上周的示例建议将 nonce 存储几个月或几年,这不仅为出错提供了大量机会,而且还需要将 nonce 记录到持久化存储介质中,这些介质可能会被备份并恢复,或以其他方式被置于意外状态。使用MuSig2的另一种替代方式是仅在需要时创建 nonce ,例如在接收到 PSBT 时。 nonce 可以存储在易失性内存中,仅在需要时使用,因此在发生意外情况(例如软件崩溃或断电)时,它们会被自动销毁(使其无法重用)。

然而,致力于解决这个问题的密码学家们似乎对原始 MuSig 协议(MuSig1)和 MuSig2 中缺乏万无一失的方法来防止 nonce 重用感到非常担忧。MuSig-DN(确定性 nonce )确实提供了解决方案,但它复杂且速度较慢(一个 alpha 版本在 2.9 GHz 的 Intel i7 处理器上生成 nonce 证明几乎需要一秒钟;我们不知道在16 MHz硬件签名设备上,使用一个处理器不那么先进的设备需要多长时间)。

我们给所有实施多重签名签署的人提供的建议是,在进行任何重大时间或资源投入之前,考虑前往 #secp256k1 IRC 聊天室或比特币密码学家聚集的其他地方,描述您的计划。

签名适配器

最初发表于 Newsletter #162

想象有人提出,如果有人能猜出他最喜欢的一个非常大的数字,他将向某个特定的慈善机构捐赠 1,000 BTC。捐赠者可以通过以下简单的方法实现这一目标:创建一笔支付 1,000 BTC 的未签名交易,然后发布该交易的签名的加密版本,其中最喜欢的数字作为解密密钥。

理论上,任何人只要猜对了这个数字,就可以解密签名并广播交易,从而支付给慈善机构。然而,如果捐赠者使用 AES 等标准加密方案,在解密之前,第三方无法轻松验证该签名是否对该交易有效。因此,任何想投入精力猜测数字的人都必须信任捐赠者的诚意,而不是一个恶作剧者。

让我们把这个问题再扩展一点。第三方 Alice 和 Bob 想要就签名是否会被公布进行下注。他们或许可以要求签名者提供签名的哈希值,并将其用作 HTLC 的哈希值,但这仍然要求信任捐赠者的诚实行为。即使签名最终被公布,捐赠者仍可以通过提供错误的哈希值来破坏 Alice 和 Bob 的合约。

适配器签名的魔法

适配器签名(也常被称为 adaptor signatures一次性可验证加密签名)可以解决这些问题——事实上,它还能解决当今比特币系统中许多实际遇到的问题。虽然适配器签名可以与比特币当前的 ECDSA 签名方案一起使用,但在 BIP340 定义的 Schnorr 签名(用于 Taproot)的实现中,适配器签名的使用会更加私密且无需额外成本。让我们看看,如果使用适配器签名,上述示例会发生怎样的变化。

与之前一样,捐赠者准备了一笔 1,000 BTC 的交易。他们的签名过程与通常方式几乎相同,唯一的不同点是,他们会以两部分生成随机数(nonce):一个真正的随机数(将永远保密),以及他们最喜欢的数字(起初也是保密的,但其他人发现它是安全的)。捐赠者使用这两个值生成一个完整的有效签名,将它们相加作为单个随机数。

BIP340 签名承诺使用随机数的两种形式:一个数值表示(称为 标量),通常只有签名者知道;以及一个椭圆曲线(EC)上的 ,用于公示以支持验证。

捐赠者从其有效签名的承诺部分中减去隐藏的标量。这使得签名变得不完整(因此无效),但允许捐赠者共享(无效的)签名承诺、(有效的)完整随机数的椭圆曲线点,以及(有效的)隐藏数字的椭圆曲线点。这三部分信息共同构成了一个适配器签名

使用 BIP340 签名验证算法的一个小变种,任何人都可以验证该适配器签名是否能通过简单地将隐藏的标量加回当前无效的签名承诺来提供一个有效签名。即使不知道隐藏的数字是什么,这也是可以验证的。简而言之,现在用户可以无需信任地开始猜测隐藏标量的值,确保他们只要猜对,就能获得签名并发送交易。

像所有收到捐赠者适配器签名的人一样,Alice 和 Bob 现在也得到了隐藏数字的椭圆曲线点。同样,他们不知道实际的标量。但请记住,捐赠者只是通过从签名承诺中减去隐藏数字来使签名变得无效,同时仍然让签名承诺包含隐藏数字的椭圆曲线点。Alice 也可以通过类似的方式创建一个无效签名:她可以创建自己的随机数对,在生成(无效的)签名时使用其私有部分,但在签名中承诺使用她的公有随机数与捐赠者适配器签名中的椭圆曲线点的聚合。这将生成一个支付给 Bob 的适配器签名。如果 Bob 知道隐藏的标量,他可以将该适配器签名转换为有效签名,并发送交易,从而赢得赌注。

那么,Bob 如何得知中奖数字?他是否必须等待某个猜对的人发布新闻稿?不需要。请再次回忆,捐赠者发布的适配器签名是他们的实际签名减去标量。当隐藏数字被发现,有人发送 1,000 BTC 交易时,他们必须发布原始(有效的)签名承诺。Bob 可以取该(有效的)签名承诺,并从中减去原始适配器签名中的(无效)签名承诺,以得出标量。然后,他可以使用该标量将 Alice 的适配器签名转换为有效签名。

多签适配器

前一节展示了个体用户如何调整其签名方式以生成适配器签名。此外,多方多签也可以使用相同的技巧。这一点极为重要,因为许多使用适配器签名的场景都需要两方的协作。

例如,在 Alice 和 Bob 进行上述赌注时,他们可以首先将资金存入一个只能由他们两人联合签名的脚本地址。然后,Alice 可以以适配器签名的形式生成她的部分签名;如果 Bob 发现隐藏的数字,他可以将 Alice 的适配器转换为她的有效部分签名,并再提供他的部分签名,以生成完整的签名来花费这些资金。

这使得适配器签名继承了多签的所有优势:它们看起来与单个签名相同,占用的空间也相同,从而最小化手续费并最大化隐私性和可替代性。

在下周的 为 Taproot 做准备 专栏中,我们将探讨适配器签名的一种主要应用场景:点时间锁合约(PTLCs),这是一种对广泛用于闪电网络、币交换以及其他协议中的哈希时间锁合约(HTLCs)的升级改进。

PTLCs

最初发表于 Newsletter #163

上周的专栏中,我们探讨了签名适配器,以及 TaprootSchnorr 签名的激活将如何使适配器的使用更加私密和高效。签名适配器可以在比特币上以多种方式应用,其中最直接受益的用例之一是点时间锁定合约(Point Time Locked Contracts,简称 PTLCs),它可以替代多年来使用的哈希时间锁定合约(HTLCs)。这将带来多个优势,但也伴随着一些挑战。为了理解两者,我们首先从一个简化的 HTLC 示例开始,该示例适用于链下 LN 支付、链上 CoinSwap,或像 Lightning Loop 这样结合链上和链下的混合系统——正是这种灵活性,使得 HTLC 被广泛使用。

Alice 想通过 Bob 向 Carol 支付,但 Alice 和 Carol 都不想信任 Bob。Carol 生成一个随机的前镜像(preimage),并使用 SHA256 算法对其进行哈希。然后,Carol 将哈希值提供给 Alice,并保留前镜像的秘密。Alice 发起支付给 Bob,Bob 可以使用自己的公钥签名加上前镜像来领取资金;或者,在 10 个区块后,Alice 可以使用自己的公钥签名将交易退还给自己。以下是用 Minsc 语言描述的该 HTLC 逻辑

(pk($bob) && sha256($preimage)) || (pk($alice) && older(10))

随后,Bob 可以使用几乎相同的脚本向 Carol 发起支付(可能扣除一些费用),但角色相应调整,并且退款超时更短:

(pk($carol) && sha256($preimage)) || (pk($bob) && older(5))

现在,Carol 可以在 5 个区块内使用前镜像领取来自 Bob 的付款,这会将前镜像暴露给 Bob,使得 Bob 也能在 5 个区块内使用它向 Alice 领取付款。

HTLC 的隐私问题

如果上述脚本在链上发布,由于相同的哈希和前镜像被重复使用,观察者可以立即看出 A 通过 B 向 C 付款。这对于同链和跨链的 CoinSwap 可能是个重大问题。不那么明显的是,这对 LN 等链下路由协议也是个问题。如果一个路径较长的支付中,有人控制多个跳数,他们可以通过检测相同的哈希和前镜像的重复使用来识别哪些节点是路由节点,从而推测出其余节点很可能是支付方或接收方。这是 可链接性问题(linkability problem)的一个组成部分,而这可能是 LN 目前最大的隐私弱点。

HTLC 可链接性问题示意图

虽然多路径支付(MPP)在一定程度上缓解了 LN 付款金额的可链接性问题,但它可能会加剧哈希可链接性问题,因为它给了监听节点更多机会来关联哈希值。

HTLC 的另一个问题是,任何需要链上执行的脚本都会与普通的支付脚本明显不同。这使得监测者更容易识别使用模式,并可能有效推测特定用户的信息。

PTLC 解决方案

在前面的 Minsc 脚本中,我们使用了一个函数,只有在传入一个预先选择的特定值(前镜像)时,该函数才会返回 true。而签名适配器(signature adaptors) 也有类似的特性——它们只有在传入一个特定值(标量)时,才能转换成有效签名。如果暂时忽略多重签名,我们可以将 HTLC 脚本转换为以下 PTLC 形式:

(pk($bob) && pk($alice_adaptor)) || (pk($alice) && older(10))
(pk($carol) && pk($bob_adaptor)) || (pk($bob) && older(5))

简单来说,Carol 给 Alice 一个椭圆曲线(EC)点,它对应一个隐藏的标量。Alice 使用该点和她选择的公钥创建一个签名适配器并交给 Bob;Bob 再使用相同的点和自己选择的公钥创建另一个适配器交给 Carol。Carol 通过转换 Bob 的适配器为有效签名来揭示标量,从而领取 Bob 的资金。随后,Bob 从 Carol 的有效签名中恢复该标量,并使用它转换 Alice 的适配器为有效签名,以领取 Alice 的资金。

这解决了链上监测的可链接性问题,因为区块链上展示的只是不同公钥对应的有效签名。第三方无法知道是否使用了适配器签名,更无法得知适配器的标量值。

然而,上述流程并不能防止参与路由的监听节点关联支付。如果所有支付都基于相同的标量,它们的可链接性就与使用哈希锁和前镜像一样高。为了解决这个问题,每个路由节点可以选择自己的标量,并在支付通过该节点时移除相应的点。我们修改示例如下:

和之前一样,Carol 给 Alice 一个点,但这次 Alice 还向 Bob 请求一个点。Alice 构造的适配器包含 Carol 的点和 Bob 的点的聚合。Bob 知道自己的点,因此可以从 Alice 传来的适配器中移除它。这样,Bob 得到的结果(他不知道的是,这实际上只是 Alice 从 Carol 那里获得的点),用于创建他给 Carol 的适配器。Carol 知道最终的标量,所以可以转换 Bob 的适配器为有效签名。Bob 从 Carol 的签名中恢复 Carol 的标量,并结合自己的标量转换 Alice 的适配器为有效签名。

在 Alice→Bob 和 Bob→Carol 这两个跳数中,使用了不同的 EC 点和标量,消除了可链接性。扩展到更长的路径后,我们可以看到隐私性的改进:

PTLC 取消可链接性示意图

正如上周提到的,Schnorr 签名使得将适配器签名与多重签名结合变得简单。对于一般的 PTLC,这使得链上的脚本可以进一步简化为:

pk($bob_with_alice_adaptor) || (pk($alice) && older(10))
pk($carol_with_bob_adaptor) || (pk($bob)   && older(5) )

在 Taproot 方案下,左分支可以成为密钥路径(keypath),右分支可以成为 Tapleaf。如果支付成功路由,Bob 和 Carol 可以在链上结算,而无需对手方进一步配合,从而使此类路由支付与单签支付、普通多重签名支付和合作解决的合约难以区分,同时还能最大化节省区块空间。如果需要执行退款条件,这种方式仍然相当高效,并具有良好的隐私性——pk(x) && older(n) 代码与降级多签强制持币等多种可能的脚本难以区分。

在下周的专栏中,我们将邀请一位我们最喜爱的 LN 开发者撰写客座文章,讨论 LN 采用密钥路径支付、多重签名、PTLCs 以及 Taproot 启用的其他特性的必要变更。

使用 Taproot 的闪电网络

最初发表于 Newsletter #164

ZmnSCPxj,闪电网络协议开发者

本文将探讨 Taproot 为闪电网络带来的两大隐私特性:

  • 闪电网络上的 PTLCs
  • P2TR 通道

闪电网络上的 PTLCs

PTLC 可实现多项功能,其中对闪电网络而言,最大优势在于无需路径随机化即可实现支付解关联3在单路径或多路径支付中,每个节点均可获得用于调整转发 PTLC 的特定参数,实现支付解关联,此举可消除各转发节点通过唯一哈希值关联具体支付的可能性。

需明确,PTLC 并非隐私万能解。若监控节点观察到特定时间锁和金额的支付转发后,短期内发现另一节点转发具有更短时间锁稍小金额的支付,这些事件极可能为同一支付路径的组成部分(即便无法通过哈希值唯一标识进行关联)。然而,变更带来以下优势:

  • 分析难度提升:监控节点依据的关联概率降低,其信息价值相应减少。
  • 多路径支付的解关联增强:不同路径间的时间锁与金额关联性大幅减弱,且若闪电网络持续发展,海量支付将削弱时序关联的有效性。
  • 成本未增加:相较于 HTLC,PTLC 无需额外开销(甚至可能因多签效率优化稍有节约)。

理论而言,无需关闭现有通道即可通过链下交易将预-Taproot 通道升级至支持 PTLC。现有通道可通过将非 Taproot 资金输出转移至含 PTLC 的 Taproot 输出实现兼容。因此,用户无需承担额外成本,仅需节点及其通道对端升级软件即可支持 PTLC。

但 PTLC 的实际使用需支付路径中所有节点均支持该协议。这意味着需足够多节点完成升级后方可广泛采用。这些节点未必需支持同一 PTLC 协议(允许存在多个协议),但均须至少支持一种。协议多样化将增加维护负担,开发者期望尽量减少协议数量(理想状态为单一协议)。

P2TR 通道

提升基础层与闪电网络层解关联的方案之一是未公开通道——此类通道不在闪电网络的 gossip 协议中广播。

但当前预-Taproot 的比特币网络中,所有 2-2 多签脚本均需明示编写。闪电网络作为 2-2 多签的最大用户,其通道的关闭交易极易被区块浏览器识别为闪电网络的链上活动,进而被追溯资金流向。任何新生成的 P2WSH 输出极可能为另一未公开通道。因此,未公开通道一旦关闭,仍存在链上识别的可能(伴随误判率)。

Taproot 借助 schnorr 签名使 n-of-n 多签交易与 1-of-1 单签交易在链上表现无异。经技术优化后,k-of-n 多签交易亦可实现等价匿名性。因此,我们可采用 Taproot 地址(即 P2TR 通道)作为闪电通道的链上基础,提升未公开通道的链上隐私4

此(微小)隐私提升同样惠及公开通道。公开通道仅在存续期广播,监控者无法获取历史通道信息。若需追踪所有公开通道,需自行存储全部数据,无法依赖”归档”节点。

此外,Taproot 密钥路径交易比现有闪电网络 P2WSH 交易体积减少 38.5 vbytes(40%)。但需注意,现有 pre-taproot 通道无法升级至 P2TR 通道,因现有通道采用 P2WSH 2-2 模式,必须关闭后重新开启 P2TR 通道。

理论上,资金输出形式仅关乎通道双方节点。其他节点无需关心通道保证金的技术细节。但公开通道需通过 gossip 网络广播。节点收到通道信息后,将查询其信任的比特币全节点验证资金 UTXO 的存在性及地址正确性。地址验证机制可抵御垃圾通道的传播——需真实资金支撑才能发布通道信息。因此实践中,P2TR 通道仍需一定程度的远程兼容性,否则发送方将因无法验证存在性而忽略此类通道。

时间预估

在去中心化开源项目中,最佳时间预测法为参考历史类似功能的开发周期。近期重大特性中,与闪电网络 PTLC 复杂度相当的是 dual funding 协议。Lisa Neigut 在 BOLTs #524 中提出初始方案后,历时两年半完成首个主网 dual funding 通道。鉴于 PTLC 需全网路径节点兼容(包括接收方),预估在具体协议提案后需三年零九个月实现广泛采用。

P2TR 通道虽仅需两节点支持,但其收益较低,故开发优先级受限。多数开发者将优先实现 PTLC 支持,预计 P2TR 通道的开发将在 SIGHASH_ANYPREVOUT 或 Decker-Russell-Osuntokun(Eltoo)方案落地后展开。

使用 Taproot 的保险库

最初发表于 Newsletter #165

Antoine PoinsotRevault 开发者

比特币保险库是一种需要两笔连续交易才能使用户从钱包中支出资金的合约。已经提出了许多此类协议(单方或多方,有或没有契约),因此我们将重点讨论它们的共同点。

与通过单一链上交易执行多次支付的批量支付相反,保险库使用多笔交易来执行一次支付。第一笔交易,即 unvault,支付给:

  1. 在相对时间锁后的一组公钥,或
  2. 没有任何时间锁的单个公钥。

第一种支出路径是主路径,预计将与“热”密钥一起使用。第二种支出路径允许进行取消交易(有时称为回收恢复重新保险库化交易)。

因此,比特币保险库与 Taproot 的洞察相反,后者认为大多数合约都有一个合作签名的“顺利路径”(争议路径通常包含时间锁)。比特币保险库恰恰相反。支出 交易必须使用 Taproot 脚本发送路径,因为它受到相对时间锁的限制5,而 取消 交易理论上可以使用密钥支出路径。

由于多方保险库在实践中已经需要大量交互,它们理论上可以受益于通过 BIP340 实现的交互式多签名门限签名方案,例如 Musig2。然而,这些方案也带来了新的安全挑战。由于保险库协议旨在用于冷存储,设计选择更为保守,因此保险库可能会是最后一个使用这些新技术的协议。

通过切换到 Taproot,保险库还可以受益于隐私和效率的轻微改进,得益于使用梅尔克分支和更短的 BIP340 签名(尤其是对于多方签名)。例如,在一个包含 6 个“冷”密钥和 3 个“活跃”密钥(门限为 2)的多方设置中,unvault 输出脚本可以表示为深度为 2 的 Taproot,叶子如下:

  • <X> CSV DROP <active key 1> CHECKSIG <active key 2> CHECKSIGADD 2 EQUAL
  • <X> CSV DROP <active key 2> CHECKSIG <active key 3> CHECKSIGADD 2 EQUAL
  • <X> CSV DROP <active key 3> CHECKSIG <active key 1> CHECKSIGADD 2 EQUAL
  • <cold key 1> CHECKSIG <cold key 2> CHECKSIGADD <cold key 3> CHECKSIGADD <cold key 4> CHECKSIGADD <cold key 5> CHECKSIGADD <cold key 6> CHECKSIGADD 6 EQUAL

在 Taproot 中,只需要揭示用于支出输出的叶子,因此交易的重量显著小于等效的 P2WSH 脚本:

IF
  6 <cold key 1> <cold key 2> <cold key 3> <cold key 4> <cold key 5> <cold key 6> 6 CHECKMULTISIG
ELSE
  <X> CSV DROP
  2 <active key 1> <active key 2> <active key 3> 3 CHECKMULTISIG
ENDIF

尽管在成功支出时撤销分支可以被隐藏(如果使用多签门限,它的存在和参与者的数量也会被模糊化),但隐私提升是有限的,因为保险库的使用模式在链上将是显而易见的。

最后,像大多数预签名交易协议一样,保险库协议将极大受益于基于 Taproot 的进一步比特币升级,例如 BIP118SIGHASH_ANYPREVOUT。尽管这需要进一步的谨慎和协议调整,ANYPREVOUTANYPREVOUTANYSCRIPT将使取消签名可重新绑定,这将大大减少交互性并允许 0(1) 的签名存储。这对 Revault 协议 中的紧急签名尤为有趣,因为它将大大减少 DoS 攻击面。通过在输出中使用ANYPREVOUTANYSCRIPT签名,您实际上是在创建一个契约,通过限制该交易支出此币时如何创建其输出。未来更具可定制性的签名哈希将允许更灵活的限制。

备份与安全方案

最初发表于 Newsletter #166

上周专栏中,Antoine Poinsot 描述了 taproot 如何提升保险库式资金备份与安全方案的隐私性和手续费效率。本周我们将探讨其他几种可通过迁移至 taproot 获得改进的备份与安全方案。

  • 简单 2-of-3:前文所述,结合多签和脚本路径支出,可轻松创建 2-of-3 支出策略。正常情况下其链上效率与单签支出相当,且比当前 P2SH 和 P2WSH 多签方案更隐私。异常情况下的效率和隐私性也表现良好。这使 taproot 成为从单签钱包升级到多签策略的理想选择。

    我们预计未来的门限签名技术将进一步优化 2-of-3 及其他 k-of-n 场景。

  • 降级多签: Optech Taproot 研讨会中的练习可体验创建支持以下规则的 taproot 脚本:随时由三个密钥支出;三天后由原密钥中的两个支出;十天后仅需一个原密钥(该练习还涉及备份密钥,我们将在下一点单独讨论)。调整时间参数和密钥设置可构建灵活强大的备份方案。

    例如,假设正常支出需笔记本电脑、手机和硬件签名设备三者协同。若其中一设备不可用,等待一个月后可用剩余两设备支出。若两设备不可用,六个月后仅需一设备即可支出。

    正常三设备协同使用时,链上脚本实现最高效和隐私。其他情况下效率略降但仍保持合理隐私性(脚本及其树深与其他合约相似)。

  • 社交恢复备份与安全: 上述示例在设备被盗时提供良好保护,但若两设备同时被盗呢?若钱包使用频繁,设备丢失后需等待一个月才能恢复支出是否合理?

    taproot 可便捷、低成本且隐私地添加社交元素。除上述脚本外,还可允许:两设备加两位亲友签名即时支出;或单一密钥加五位信任者签名即时支出(非社交版本可使用额外设备或备份助记词)。

  • 时间与社交阈值结合的继承方案: 综合上述技术,可设置在你突发意外时允许指定个人或群体恢复资金。例如,若比特币六个月未移动,允许律师和五位亲属中的三位支出。若你本就每六个月操作资金,该继承方案在你生前无额外链上成本且对外完全隐私。甚至可让律师和亲属在你生前无法知晓交易详情(只需确保他们能在你离世后获取钱包的扩展公钥 xpub)。

    请注意,继承人具备技术能力支出比特币不等同于合法继承。建议计划比特币继承者阅读 Pamela Morgan 的《加密资产继承规划》(实体书/DRM 电子书DRM-free 电子书),并与本地遗产规划专家讨论细节。

  • 入侵检测: taproot 诞生前提出的树签名方案建议在所有设备上放置控制少量比特币的密钥作为入侵检测。若金额足够诱人,攻击者可能选择立即盗取而非长期潜伏造成更大损失。

    该方案的挑战在于:需设置足够吸引攻击者的金额,但又不愿在每台设备存放大量比特币(希望仅提供一份高额赏金)。若所有设备使用相同密钥,攻击交易无法定位被入侵设备。taproot 允许为每台设备设置不同密钥和脚本路径。任一密钥均可支出全部资金,同时精确定位被入侵设备。

在 Signet 上测试

最初发表于 Newsletter #167

尽管你无法在主网区块 709,632 前安全使用 Taproot,但你现在可以通过 testnet 或 signet 使用 Taproot。与使用 Bitcoin Core 的 regtest 模式创建本地测试网络(如 Optech Taproot 工作手册 所示)相比,使用 testnet 或 signet 能更方便地测试你的钱包与其他用户钱包的交互。

本文将演示如何在 signet 上使用 Bitcoin Core 内置钱包接收和花费 Taproot 交易。你可以根据这些指令调整,以测试你的钱包与 Bitcoin Core 之间的收发功能。

虽然 Bitcoin Core 22.0 的内置钱包技术上支持收发 Taproot 交易,但我们建议你编译 Bitcoin Core 的拉取请求 #22364,该请求将 Taproot 设为描述符钱包的默认选项。编译完成后,启动 signet:

$ bitcoind -signet -daemon

如果是首次使用 signet,需同步其区块链。当前数据量不足 200 MB,可在约一分钟内完成同步。可通过 getblockchaininfo RPC 监控同步进度。同步完成后,创建描述符钱包:

$ bitcoin-cli -signet -named createwallet wallet_name=p4tr descriptors=true load_on_startup=true
{
  "name": "p4tr",
  "warning": "此钱包为实验性描述符钱包"
}

现在可生成 bech32m 地址:

$ bitcoin-cli -named -signet getnewaddress address_type=bech32m
tb1p6h5fuzmnvpdthf5shf0qqjzwy7wsqc5rhmgq2ks9xrak4ry6mtrscsqvzp

使用该地址可从 signet faucet 获取测试币。需等待交易确认,时间与主网类似(通常 30 分钟内,有时更长)。查看交易详情时,会注意到创建的 P2TR 脚本:

$ bitcoin-cli -signet getrawtransaction 688f8c792a7b3d9cb46b95bfa5b10fe458617b758fe4100c5a1b9536bedae4cd true | jq .vout[0]
{
  "value": 0.001,
  "n": 0,
  "scriptPubKey": {
    "asm": "1 d5e89e0b73605abba690ba5e00484e279d006283bed0055a0530fb6a8c9adac7",
    "hex": "5120d5e89e0b73605abba690ba5e00484e279d006283bed0055a0530fb6a8c9adac7",
    "address": "tb1p6h5fuzmnvpdthf5shf0qqjzwy7wsqc5rhmgq2ks9xrak4ry6mtrscsqvzp",
    "type": "witness_v1_taproot"
  }
}

接下来可生成第二个 bech32m 地址并发送资金以测试花费功能:

$ bitcoin-cli -named -signet getnewaddress address_type=bech32m
tb1p53qvqxja52ge4a7dlcng6qsqggdd85fydxs4f5s3s4ndd2yrn6ns0r6uhx
$ bitcoin-cli -named -signet sendtoaddress address=tb1p53qvqxja52ge4a7dlcng6qsqggdd85fydxs4f5s3s4ndd2yrn6ns0r6uhx amount=0.00099
24083fdac05edc9dbe0bb836272601c8893e705a2b046f97193550a30d880a0c

查看该花费交易的输入部分,可见其见证数据仅包含一个 64 字节的签名。这比 P2WPKH 或其他传统比特币交易所需的见证数据更精简(以虚拟字节计)。

$ bitcoin-cli -signet getrawtransaction 24083fdac05edc9dbe0bb836272601c8893e705a2b046f97193550a30d880a0c true | jq .vin[0]
{
  "txid": "bd6dbd2271a95bce8a806288a751a33fc4cf2c336e52a5b98a5ded432229b6f8",
  "vout": 0,
  "scriptSig": {
    "asm": "",
    "hex": ""
  },
  "txinwitness": [
    "2a926abbc29fba46e0ba9bca45e1e747486dec748df1e07ee8d887e2532eb48e0b0bff511005eeccfe770c0c1bf880d0d06cb42861212832c5f01f7e6c40c3ce"
  ],
  "sequence": 4294967294
}

通过实践上述指令,你将能轻松在任何支持 signet 的钱包中测试 Taproot 的收发功能。

仍需 Signmessage 协议

最初发表于 Newsletter #168

自四年前隔离见证(segwit)激活以来,尚未形成被广泛接受的为 Bech32 或 Bech32m 地址创建签名消息的方式。可以说,我们现在可以认为广泛的消息签名支持对用户或开发者而言并不十分重要,否则会有更多工作投入其中。但相较于过去使用传统地址时用户可便捷交换签名消息的情况,比特币钱包软件的功能似乎有所倒退。

我们在两年前关于 Bech32 消费支持 系列文章中提到的通用 Signmessage 方案进展甚微,即便其协议文档 BIP322 偶有更新(参见 Newsletter #118#130),也未被 Bitcoin Core 采用。尽管如此,我们尚未发现更优替代方案,因此任何希望在 P2TR 钱包中添加 Signmessage 功能的开发者仍应将 BIP322 作为首选。

若得以实现,通用 Signmessage 协议将支持为以下类型的 P2TR 输出签名:纯单签、使用多签或任何 Tapscript 脚本。该协议还将向后兼容所有传统及 Bech32 地址,并向前兼容目前规划的近期变更类型(部分内容将在后续为 Taproot 激活做准备专栏中预告)。能够访问完整 UTXO 集的应用(例如通过全节点)还可利用 BIP322 生成和验证储备证明,以证明签名者在特定时间点控制特定数量的比特币。

实现通用签名消息功能的创建相对简单。BIP322 采用称为虚拟交易的技术:首笔虚拟交易通过尝试花费不存在的先前交易(txid 全为零)构造为无效交易,该交易支付至用户需签名的地址(脚本)并包含对目标消息的哈希承诺;第二笔交易花费首笔交易的输出——若该花费的签名及其他数据构成有效交易,则视为消息已签名(尽管第二笔虚拟交易仍无法上链,因其源自无效的前序交易)。

对多数钱包而言,验证通用签名消息更为复杂。要完全验证任意 BIP322 消息需实现比特币几乎所有的共识规则。多数钱包不具备此能力,因此 BIP322 允许其在无法完整验证脚本时返回”不确定”状态。实践中,尤其是 Taproot 鼓励密钥路径花费的背景下,这种情况可能较少。任何仅实现几种常用脚本类型的钱包将能验证超过 99% UTXO 的签名消息。

通用 Signmessage 支持将是比特币的一项有益补充。尽管过去数年其受关注度不足,我们仍鼓励阅读本文的钱包开发者考虑为您的程序添加实验性支持。这是为用户恢复已缺失数年的功能的便捷途径。若您是参与 BIP322 或相关储备证明实现的开发者,或认为此类功能有价值的服务提供商,欢迎联系 info@bitcoinops.org 以协调合作。

输出关联

最初发表于 Newsletter #169

在 taproot 激活后,用户将开始接收支付至 P2TR 输出的交易。随后,他们将花费这些输出。某些情况下,用户可能向非 P2TR 输出支付,但仍会使用 P2TR 找零输出将剩余资金返还给自己。

示例交易 P2TR -> {P2WPKH、P2TR}

对于观察此类交易的专家或算法而言,可以合理推断 P2TR 输出是用户自身的找零输出,而其他输出则为支付输出。虽然这并非绝对成立,但属于最可能的解释。

有观点认为,由于钱包向 P2TR 过渡期间可能出现的隐私暂时下降,应当忽略 taproot 的诸多隐私优势。多位专家指出这种担忧属于过度反应。我们认同此观点,并补充以下考量:

  • 其他元数据:​​ 交易可能包含其他揭示找零与支付输出的元数据。最令人担忧的是当前大量存在的地址复用现象,严重损害交易双方的隐私。只要这些问题存在,拒绝为遵循最佳实践的钱包和服务用户实施重大隐私升级便显失明智。

  • 输出脚本匹配:​​ Bitcoin Core 内置钱包默认在支付输出包含隔离见证类型时使用隔离见证找零输出,否则使用默认找零地址类型。例如支付至 P2PKH 输出时可能使用 P2PKH 找零,支付至 P2WPKH 输出时使用 P2WPKH 找零。如周报 #155所述,taproot 激活后 Bitcoin Core 将在交易包含其他 P2TR 输出时优先使用 P2TR 找零输出,最大程度减少过渡期找零可识别性的增加。

  • 请求升级:​​ P2TR 为比特币历史首次提供了机会,让所有用户无论安全需求如何均使用相同类型的输出脚本,并频繁使用不可区分的输入,显著提升隐私。若期望提升比特币隐私,可要求收款方和服务提供商支持 taproot(并停止地址复用)。若双方均完成升级,找零输出将更难以识别,同时还能获得 taproot 的其他卓越隐私优势。

合作永远是可行选项吗?

最初发表于 Newsletter #170

Gregory Maxwell 在最初的 taproot 提案中提出了一个有趣的合约设计原则:

“几乎所有有趣的脚本都有一个逻辑顶层分支,允许所有参与者仅通过签名即可完成合约执行。其他分支仅在部分参与者不配合时使用。更加强调地说,我认为任何预先确定固定有限参与者的合约都应该表示为 N-of-N 签名与其他复杂合约条件的 OR 组合。”(原文强调)

此后,专家们就此原则的普适性展开辩论,目前已知的两个例外情况均与时间锁相关:

  • 共识强化的自我控制:​​ 部分用户使用时间锁阻止自己在特定期限内花费比特币。时间锁要求看似需要除签名外的额外条件,但存在以下争议:

    • 极度渴求资金的用户可通过其他资产担保获得贷款,这削弱了此类自控合约的效用。

    • 除共识强制的脚本路径时间锁外,用户可设置密钥路径支出,允许自身密钥与第三方密钥(仅在时间锁到期后签名)共同签署。这种方式不仅更高效,还能实现更灵活的支出策略,例如允许用户出售分叉币,或在重大生活变故或价格波动时通过第三方提前支取。

  • 保险库:​​ 如 Antoine Poinsot 几周前在本站的专栏所述,保险库也广泛使用时间锁保护资金,这似乎”与 taproot 的核心洞见(即多数合约存在参与者协同签名的理想路径)相悖”。但有观点认为,保险库用户始终需要密钥路径作为逃生通道,且为脚本路径合约添加密钥路径选项无需额外成本,因此具备绝对优势。

反对始终提供密钥路径的观点认为,即使所有签名者共同行动,仍存在不信任自身的情况。他们转而信任其他主体——执行比特币共识规则的经济全节点运营者——来强制执行签名者不愿自我施加的支出限制。

反驳观点指出,至少在理论上,可以通过在常规签名者与所有经济全节点运营者之间创建密钥路径多签来获得同等安全性。更实际地说,或许存在某个节点运营者子集可加入密钥路径多签集来执行所需策略(若不可行,用户仍可通过脚本路径支出,因此并无损失)。

抛开理论探讨,我们建议在设计基于 taproot 的合约时,即使看似无需密钥路径,也应额外考量是否存有利用密钥路径的机会。

琐事

最初发表于 Newsletter #171

  • 什么是 Taproot? 维基百科解释:”主根(taproot)是一种大型、中心化且占主导地位的根系,其他根须从其侧面生长。典型的主根较为笔直粗壮、呈锥形且垂直向下生长。某些植物(如胡萝卜)的主根作为储存器官高度发达,已被培育为蔬菜。”

    这与比特币有何关联?

    • “我一直认为这个名字源于’接入默克尔根(taps into the Merkle root)’,但实际并不清楚 Gregory Maxwell 的命名思路。” ——Pieter Wuille(来源

    • “我最初不得不查阅这个词的含义;但将其理解为密钥路径是’主根’,因为这是可食用的部分(用于制作胡萝卜汤),而默克尔化的脚本则是其他次要根须(希望被忽略)。” ——Anthony Towns(来源

    • “该名称源自对蒲公英主根般粗壮中心树干的视觉化想象——该技术的主要价值在于假设存在一条高概率路径(其他为杂乱次要路径)。此外,’taproot’ 的双关含义也贴切,因为其通过根部的隐藏承诺来验证脚本路径支付。

      […] 可惜,将带有排序内部节点的哈希树称为’myrtle 树’(取自桃金娘科,含茶树等)并未流行,尽管其发音类似’merkle’且有数学排列特性。” ——Gregory Maxwell(来源

  • Schnorr 签名早于 ECDSA:​ 尽管我们将 schnorr 签名 视为比特币原始 ECDSA 签名的升级(因其更易实现密码学技巧),但 schnorr 签名算法其实早于 ECDSA 所基于的 DSA 算法。事实上,DSA 的创建部分是为了规避 Claus Peter Schnorr 的 schnorr 签名专利,但 Schnorr 仍声称“我的专利适用于各类离散对数签名实现,包括 Nyberg-Rueppel 和 DSA”。目前无法院支持此主张,且其专利已于 2011 年过期。

  • 命名争议:​ 在比特币采用 schnorr 签名的早期,曾有建议避免使用 Schnorr 之名,因其专利阻碍了该密码学技术的普及。Pieter Wuille 解释:”我们曾考虑将 BIP340 命名为’DLS’(离散对数签名),但最终因 Schnorr 之名已被广泛讨论而未采纳。”

  • 扭曲爱德华曲线的 Schnorr 签名:​ 2011 年发布的 EdDSA 方案将 schnorr 签名应用于椭圆曲线,现已成为多项标准的基础。虽然未用于比特币共识层,但 Optech 追踪的多个比特币代码库中可见其相关引用。

  • 支付到合约:​ Ilja Gerhardt 和 Timo Hanke 在 2013 年圣何塞比特币大会上提出的协议允许支付承诺至合约哈希。持有合约和防攻击随机数的任何人都可验证该承诺,但对他人而言该支付与普通比特币支付无异。

    2014 年侧链论文中的改进版 P2C 额外承诺原始公钥。Taproot 采用相同结构,但其承诺对象为接收方设定的链上花费条件(而非链下合约条款)。

  • 灵感诞生地:​ 使脚本支付与公钥支付在链上表现相同的 P2C 创意,由 Andrew Poelstra 和 Gregory Maxwell 于 2018 年 1 月 22 日在加利福尼亚州洛斯阿尔托斯的 “A Good Morning” 餐厅构思。Pieter Wuille 回忆:”这个想法在我暂时离开餐桌时诞生… !$%@” [原文如此]

  • 2.5 年浓缩至 1.5 天:​ 确定 bech32m 的最佳常数消耗了 2.5 年 CPU 时间,最终借 Gregory Maxwell 的 CPU 集群在 1.5 天内完成计算。

感谢 Anthony Towns、Gregory Maxwell、Jonas Nick、Pieter Wuille 和 Tim Ruffing 为本栏目提供的见解。文中错误由作者负责。

未来的共识变化

最初发表于 Newsletter #172

随着 Taproot 在区块高度 709,632 临近激活,我们可以开始展望开发者们此前希望在 Taproot 基础上构建的部分共识变更。

  • 跨输入签名聚合:​ schnorr 签名使得多个独立公私钥对的持有者能够轻松创建单个签名来证明所有密钥持有者的协作授权。 通过未来的共识变更,这将允许交易包含单个签名来证明该交易中所有被花费的 UTXO 所有者均已授权支出。这将为每个密钥路径花费(首个输入之后)节省约 16 vbytes,为资金整合和 coinjoins 带来显著空间节省。它甚至可能使得基于 coinjoin 的支出比个人单独支出更经济,为使用更隐私的支出方式提供温和激励。

  • SIGHASH_ANYPREVOUT:​ 每笔比特币交易都包含一个或多个输入,每个输入通过 txid 引用前序交易的输出。这个引用告知 Bitcoin Core 等全验证节点该交易可支出的金额及验证授权所需的条件。所有比特币交易签名生成方式(无论是否使用 Taproot)要么承诺 prevouts 中的 txid,要么完全不承诺 prevouts。

    这对不希望使用预先安排交易序列的多用户协议构成挑战。如果任何用户可以跳过特定交易,或更改除见证数据外的任何交易细节,将导致后续交易的 txid 改变。txid 的变更会使之前为后续交易创建的签名失效。这迫使链下协议实施惩罚机制(如 LN 惩罚机制)来惩戒提交旧交易的用户。

    SIGHASH_ANYPREVOUT 通过允许签名跳过对 prevout txid 的承诺来解决此问题。根据使用的其他标志,它仍会承诺关于 prevout 和交易的其他细节(如金额和脚本),但不再关心前序交易使用的 txid。这将使实现 eltoo 闪电网络层以及保险库和其他合约协议的改进成为可能。

  • 委托与通用化:​ 创建脚本(Taproot 或其他类型)后,几乎 无法在不泄露私钥的情况下委托他人使用该脚本(使用 BIP32 钱包时逆向推导可能极其危险)。此外,对于希望使用密钥路径支出加少量脚本条件的用户,Taproot 可变得更具成本效益。目前已提出多种通过通用化和提供签名者委托来增强 Taproot 的方法:

    • Graftroot:​ 在 Taproot 概念提出后不久提出,Graftroot 将为任何能够进行 Taproot 密钥路径支出的用户提供额外功能。密钥路径签名者可以不直接支出资金,而是签署描述新支出条件的脚本,将支出权限委托给能够满足该脚本的任何人。支出交易中需提供签名、脚本及满足脚本所需的任何数据。密钥路径签名者可以通过这种方式委托无限数量的脚本,且在实际支出发生前不会产生任何链上数据。

    • 通用化 Taproot(g’root):​ 数月后,Anthony Towns 提出使用公钥点承诺多种支出条件的方法,无需使用类似 MAST 的结构。这种 通用化 Taproot(g’root)构造在 “Taproot 假设不成立” 时可能更高效,同时 “提供构建软分叉安全的跨输入聚合系统的简便方法”。

    • Entroot:​ 近期综合 Graftroot 和 g’root 的方案,简化多数场景并提升带宽效率。它支持来自任何能够满足 Entroot 分支的签名者委托,而不仅限于能够创建顶层密钥路径支出的用户。

  • 新旧操作码:​ Taproot 软分叉包含对 Tapscript 的支持,通过 OP_SUCCESSx 操作码提供了改进的比特币新操作码添加方式。与比特币早期添加的 OP_NOPx(无操作)操作码类似,OP_SUCCESSx 操作码设计为可替换为不总是返回成功的操作码。部分提议的新操作码包括:

    • 恢复旧操作码:​ 2010 年因安全漏洞担忧而禁用的多个数学和字符串操作码。许多开发者希望在进行安全审查后重新启用这些操作码,并在某些情况下扩展其处理更大数值的能力。

    • OP_CAT:​ 这个曾被禁用的操作码值得特别关注,研究人员发现其单独使用即可通过密钥树后量子密码或与 OP_CHECKSIGFROMSTACK 等新操作码结合实现各类有趣功能。

    • OP_TAPLEAF_UPDATE_VERIFY:​第 166 期周报所述,OP_TLUV 操作码在配合 Taproot 密钥路径和脚本路径功能时,能高效实现强大的契约,可用于构建联合质押池保险库等安全与隐私改进方案,也可能与 OP_CHECKTEMPLATEVERIFY 良好结合。

以上所有设想仍仅为提案,无法保证最终实现。需要研究人员和开发者推动每个提案走向成熟,最终由用户决定是否值得通过改变比特币共识规则来添加这些功能。

激活时会发生什么?

最初发表于 Newsletter #173

在本文发布后不到两周时间,taproot 预计将在区块 709,632 激活。我们了解预期会发生的情况,同时也意识到几种可能的故障模式。

最理想且最可能的结果是一切顺利。普通用户不会感知到任何变化,只有那些密切监控节点或尝试创建 taproot 交易的用户会注意到差异。在区块 709,631 时,我们所知几乎所有全节点都将执行相同的共识规则。随后的区块中,运行 Bitcoin Core 0.21.1、22.0 或相关版本的节点将开始执行早期版本未包含的 taproot 规则。

这存在不同版本节点软件接受不同区块的风险。类似情况曾发生在 2015 年 BIP66 软分叉激活期间,导致六区块的链分叉及多次短暂分叉。开发团队已投入大量精力防止此类问题重演。只有在矿工故意挖出违反 taproot 规则的区块,或禁用了 Bitcoin Core 等节点软件内置的安全机制时,才可能出现类似问题。

具体而言,要制造链分叉,矿工需创建或接受未遵守 taproot 规则的花费 segwit v1 输出的交易。若发生这种情况,当比特币节点运营者的经济共识拒绝这些无效区块时,相关矿工将至少损失 6.25 BTC(约合 40 万美元)。

我们无法在未实际创建无效区块的情况下断言节点运营者的行为(节点可完全私有运行),但通过代理指标观测显示,超过 50% 的节点运营者正在运行支持 taproot 的 Bitcoin Core 版本。这足以确保任何 taproot 无效区块将被网络拒绝。

尽管可能性极低,理论上仍存在临时链分叉风险。可通过 ForkMonitor.info 等监控服务或 Bitcoin Core 的 getchaintips RPC 进行监测。若分叉发生,轻客户端可能收到错误确认。虽然理论上可能出现 6 次确认(如 2015 年分叉),但这意味着矿工将损失近 250 万美元(2015 年损失约 5 万美元)。在如此高昂代价下,我们有理由相信矿工会切实执行半年前就发出支持信号的 taproot 规则。

在几乎所有可预见的故障场景中,简单有效的临时应对措施是提高确认要求。若常规需 6 次确认接收支付,可临时提升至 30 次确认并持续数小时,直至问题解决或确认需进一步上调。

对于确信全节点运营者经济共识将执行 taproot 规则的用户和服务,更简单的解决方案是仅从 Bitcoin Core 0.21.1 或更新版本(或兼容替代实现)获取交易确认信息。

Optech 预计 taproot 激活将平稳完成,但仍建议交易所在区块 709,632 前后处理大额交易时升级节点,或准备好在出现异常迹象时临时提高确认要求。

感谢!

最初发表于 Newsletter #174

Taproot 将在区块 709,632 激活,预计于本文发布后数日内完成。作为本系列的终篇,我们谨向众多参与开发与激活 Taproot 的人士致谢——他们即将开始执行这一升级。未提及的诸多贡献者同样值得感谢,我们为所有疏漏致歉。

Bitcoin-Dev 邮件列表讨论

Taproot 的核心构想萌芽于 2019 年 1 月 22 日早晨几位密码学家的会议,并于当日通过邮件列表发布。以下人士参与了主题含 “taproot” 的讨论:

Adam Back、 Andrea Barontini、 Andreas Schildbach、 Andrew Chow、 Andrew Poelstra、 Anthony Towns、 Antoine Riard、 Ariel Lorenzo-Luaces、 Aymeric Vitte、 Ben Carman、 Ben Woosley、 Billy Tetrud、 BitcoinMechanic、 Bryan Bishop、 Carlo Spiller、 Chris Belcher、 Christopher Allen、 Clark Moody、 Claus Ehrenberg、 Craig Raw、 Damian Mee、 Daniel Edgecumbe、 David A. Harding、 DA Williamson、 Elichai Turkel、 Emil Pfeffer、 Eoin McQuinn、 Eric Voskuil、 Erik Aronesty、 Felipe Micaroni Lalli、 Giacomo Caironi、 Gregory Maxwell、 Greg Sanders、 Jay Berg、 Jeremy Rubin、 John Newbery、 Johnson Lau、 Jonas Nick、 Karl-Johan Alm、 Keagan McClelland、 Lloyd Fournier、 Luke Dashjr、 Luke Kenneth Casson Leighton、 Mark Friedenbach、 Martin Schwarz、 Matt Corallo、 Matt Hill、 Michael Folkson、 Natanael、 Oleg Andreev、 Pavol Rusnak、 Pieter Wuille、 Prayank、 R E Broadley、 Riccardo Casatta、 Robert Spigler、 Ruben Somsen、 Russell O’Connor、 Rusty Russell、 Ryan Grant、 Salvatore Ingala、 Samson Mow、 Sjors Provoost、 Steve Lee、 Tamas Blummer、 Thomas Hartman、 Tim Ruffing、 Vincent Truong、 vjudeu、 yancy、 yanmaani—— 以及 ZmnSCPxj。

Taproot 整合的 schnorr 签名MAST 等概念源起更早,我们同样感谢相关贡献者。

Taproot BIP 审查

自 2019 年 11 月起,大量用户和开发者参与了 Taproot 的系统化审查

achow101、 afk11、 aj、 alec、 amiti、 _andrewtoth、 andytoshi、 ariard、 arik、 b10c、 belcher、 bjarnem、 BlueMatt、 bsm1175321、 cdecker、 chm-diederichs、 Chris_Stewart_5、 cle1408、 CubicEarth、 Day、 ddustin、 devrandom、 digi_james、 dr-orlovsky、 dustinwinski、 elichai2、 evoskuil、 fanquake、 felixweis、 fjahr、 ghost43、 ghosthell、 gmaxwell、 harding、 hebasto、 instagibbs、 jeremyrubin、 jnewbery、 jonatack、 justinmoon、 kabaum、 kanzure、 luke-jr、 maaku、 mattleon、 michaelfolkson、 midnight、 mol、 Moller40、 moneyball、 murch、 nickler、 nothingmuch、 orfeas、 pinheadmz、 pizzafrank13、 potatoe_face、 pyskell、 pyskl、 queip、 r251d、 raj_149、 real_or_random、 robert_spigler、 roconnor、 sanket1729、 schmidty、 sipa、 soju、 sosthene、 stortz、 taky、 t-bast、 theStack、 Tibo、 waxwing、 xoyi—— 以及 ZmnSCPxj。

GitHub 拉取请求

Taproot 在 Bitcoin Core 中的主要实现于 2020 年 1 月通过两个拉取请求提交审查。以下人士参与了代码审查:

Andrew Chow (achow101)、 Anthony Towns (ajtowns)、 Antoine Riard (ariard)、 Ben Carman (benthecarman)、 Ben Woosley (Empact)、 Bram (brmdbr)、 Cory Fields (theuni)、 Dmitry Petukhov (dgpv)、 Elichai Turkel (elichai)、 Fabian Jahr (fjahr)、 Andreas Flack (flack)、 Gregory Maxwell (gmaxwell)、 Gregory Sanders (instagibbs)、 James O’Beirne (jamesob)、 Janus Troelsen (ysangkok)、 Jeremy Rubin (JeremyRubin)、 João Barbosa (promag)、 John Newbery (jnewbery)、 Jon Atack (jonatack)、 Jonathan Underwood (junderw)、 Kalle Alm (kallewoof)、 Kanon (decryp2kanon)、 kiminuo、 Luke Dashjr (luke-jr)、 Marco Falke (MarcoFalke)、 Martin Habovštiak (Kixunil)、 Matthew Zipkin (pinheadmz)、 Max Hillebrand (MaxHillebrand)、 Michael Folkson (michaelfolkson)、 Michael Ford (fanquake)、 Adam Ficsor (nopara73)、 Pieter Wuille (sipa)、 Sjors Provoost (Sjors)、 Steve Huguenin-Elie (StEvUgnIn)、 Tim Ruffing (real-or-random)、 以及 Yan Pritzker (skwp)。

Taproot 激活讨论

社区围绕激活方式展开了数月讨论,主要参与者包括:

6102bitcoin、 AaronvanW、 achow101、 aj、 alec、 Alexandre_Chery、 Alistair_Mann、 amiti、 andrewtoth、 andytoshi、 AnthonyRonning、 ariel25、 arturogoosnargh、 AsILayHodling、 averagepleb、 bcman、 belcher、 benthecarman、 Billy、 bitcoinaire、 bitentrepreneur、 bitsharp、 bjarnem、 blk014、 BlueMatt、 bobazY、 brg444、 btcactivator、 btcbb、 cato、 catwith1hat、 cguida、 CodeShark__、 conman、 copumpkin、 Crash78、 criley、 CriptoLuis、 CubicEarth、 darbsllim、 darosior、 Day、 DeanGuss、 DeanWeen、 debit、 Decentralizedb、 devrandom、 DigDug、 dome、 dr_orlovsky、 duringo、 dustinwinski、 eeb77f71f26eee、 eidnrf、 elector、 elichai2、 Emcy、 emzy、 entropy5000、 eoin、 epson121、 erijon、 eris、 evankaloudis、 faketoshi、 fanquake、 fedorafan、 felixweis、 fiach_dubh、 fjahr、 friendly_arthrop、 GeraldineG、 gevs、 gg34、 ghost43、 ghosthell、 giaki3003、 gloved、 gmaxwell、 graeme1、 GreenmanPGI、 gr-g、 GVac、 gwillen、 gwj、 gz12、 gz77、 h4shcash、 harding、 hebasto、 hiro8、 Hotmetal、 hsjoberg、 huesal、 instagibbs、 Ironhelix、 IT4Crypto、 ja、 jaenu、 JanB、 jeremyrubin、 jimmy53、 jnewbery、 jonatack、 jonny100051、 jtimon、 kallewoof、 kanon、 kanzure、 Kappa、 keblek、 ksedgwic、 landeau、 lucasmoten、 luke-jr、 maaku、 Majes、 maybehuman、 mblackmblack、 mcm-mike、 Memesan、 michaelfolkson、 midnight、 MikeMarzig、 mips、 mol、 molz、 moneyball、 mrb07r0、 MrHodl、 murch、 naribia、 newNickName、 nickler、 nikitis、 NoDeal、 norisgOG、 nothingmuch、 occupier、 OP_NOP、 OtahMachi、 p0x、 pinheadmz、 PinkElephant、 pox、 prayank、 prepaid、 proofofkeags、 provoostenator、 prusnak、 qubenix、 queip、 r251d、 rabidus、 Raincloud、 raj、 RamiDz94、 real_or_random、 rgrant、 riclas、 roasbeef、 robert_spigler、 rocket_fuel、 roconnor、 rovdi、 rubikputer、 RusAlex、 rusty、 sanket1729、 satosaurian、 schmidty、 sdaftuar、 setpill、 shesek、 shinobiusmonk、 snash779、 solairis、 somethinsomethin、 stortz、 sturles、 sugarpuff、 taPrOOteD、 TechMiX、 TheDiktator、 thomasb06、 tiagocs、 tomados、 tonysanak、 TristanLamonica、 UltrA1、 V1Technology、 vanity、 viaj3ro、 Victorsueca、 virtu、 walletscrutiny、 wangchun、 warren、 waxwing、 Whatisthis、 whuha、 willcl_ark、 WilliamSantiago、 windsok、 wumpus、 xxxxbtcking、 yanmaani、 yevaud、 ygrtiugf、 Yoghurt11411、 zmnscpxj、 以及 zndtoshi。

矿工信号

我们感谢自区块 681,408 以来所有发出 Taproot 准备就绪信号的矿工。

生态项目

Taproot 激活仅是起点,开发者与用户将开始运用其新特性。我们感谢多年筹备 MuSig 等生态项目的贡献者。

全节点运营者

最关键的致谢致予数千名 Bitcoin Core 0.21.1 及以上版本(或兼容软件)的运营者。他们通过升级节点确保从区块 709,632 开始仅接受符合 Taproot 规则的交易,为全网的升级安全提供经济保障。

脚注

  1. 当 Electrum 升级到 segwit v0 时,要求任何希望使用 bech32 地址接收资金的用户都生成新的种子。虽然这在技术上并非必要,但它使 Electrum 的作者能够在其自定义种子推导方法中引入一些新的功能。其中一个功能是允许通过种子版本号来指定一个种子应当使用的脚本。这使得旧脚本可以被安全地逐步弃用(例如,未来某个版本的 Electrum 可能会发布,它将不再支持接收到传统的 P2PKH 地址)。

    大约在 Electrum 开发者部署其版本化种子同期,Bitcoin Core 的开发者开始使用 输出脚本描述符 来解决相同的问题——允许逐步弃用脚本(同时也解决了其他问题)。下表对比了 Electrum 的版本化种子和 Bitcoin Core 的描述符与此前两者都使用的 隐式脚本 方法(目前在大多数其他钱包中仍普遍使用)。

    脚本管理 初始备份 引入新脚本 扫描(带宽/CPU 成本) 弃用脚本
    隐式脚本(例如 BIP44 种子词 自动(无需用户操作) 必须扫描所有受支持的脚本,O(n) 无法警告用户他们使用了不受支持的脚本
    显式脚本(版本化种子) 种子词(包含版本位) 用户必须备份新的种子;资金要么被拆分到两个独立钱包中,要么需要用户将旧钱包的资金转移到新钱包 只扫描单一脚本模板,O(1) 警告用户有关不受支持的脚本
    显式脚本(描述符 种子词和描述符 用户必须备份新的描述符 仅扫描实际使用过的脚本模板,O(n);对于新钱包而言 n=1 警告用户有关不受支持的脚本

  2. 若用户希望在首个 Taproot 区块接收 P2TR 支付,应生成一个不与他人共享的地址,并创建 nLockTime 设为 709,631 的交易。该交易可在收到区块 709,631 后立即广播。nLockTime 将确保交易无法在 Taproot 规则生效的 709,632 前被包含。若未充分理解新脚本类型和自定义锁定时间,此类操作可能存在风险,请谨慎处理。 

  3. 付款方可选择复杂路径(路径随机化)弱化 HTLC 关联分析,然存在弊端:

    • 复杂路径不仅成本更高且可靠性下降(需要支付更多转发节点费用,同时依赖更多节点成功完成转发)。
    • 路径延伸导致支付信息被暴露于更多节点,大幅增加遭遇监控节点的可能性。 因此路径随机化非完美隐私解决方案。

  4. 在考虑未公开通道时,记住需要“二人共舞”,如果一个未公开通道被关闭,那么其中一个参与者(例如,一个闪电网络服务提供商)将剩余的资金用于一个公开通道,区块链浏览器可以推测这些资金的来源有一定概率是曾经关闭的未公开通道。 

  5. 如果已知,您可以预签 支出 交易并指定 nSequence,但这样您就不再需要“活跃”密钥的备用支出路径。而且,通常您在收到比特币时并不知道如何花费它们。