本周的周报总结了一段在 “静默支付” 地址中添加过期时间的讨论,并概述了 “免服务器 payjoin” 的 BIP 草案。一份贡献给我们的田野调查(field report)介绍了一种基于 MuSig2 的钱包对无脚本式多签名输出的实现和部署情况。此外就是我们的常规栏目:软件的新版本和候选版本的发布公告、热门的比特币基础设施谢幕的重大变更介绍。

新闻

  • 为静默支付地址添加过期时间:Peter Todd 在 Bitcoin-Dev 邮件组中发帖,建议为静默支付的地址增加一个用户自选的过期日。不像常规的比特币地址,如果多次接收支付会导致 “输出关联”,静默支付的地址在每次正确使用时都会产生一个唯一的输出脚本。在收款方无法或者不便于在每次支付时都给支付方一个不同的常规地址时,静默支付可以显著提高隐私性。

    Peter Tode 指出,为所有地址提供过期时间都是可取的:在某些情况下,大部分用户都会停止使用一个钱包。按照预期,常规地址只会被使用一次,所以过期时间就不那么要紧;但预期会被重复使用的静默支付,就让过期标记变得更加重要。他建议,要么在地址中加入一个 2 字节的过期时间字段,以支持从当前开始计算,最长可达 180 年的过期时间;要么加入一个 3 字节的字段,从而支持从当前开始计算,最长可达 45000 年的过期时间。

    这个建议在邮件组中得到了少量的讨论,但截至本刊撰写之时,还没有明确的解决。

  • 免服务器的 payjoin:Dan Gould 在邮件组中发帖出示了 免服务器 pajoin(详见周报 #236)的一份 BIP 草案。就其自身而言,由 BIP78 定义的 payjoin 预期收款方会运行一个服务器,以安全地接收由支付方提供的 LDK。Gould 提出了一种异步中继模式,一开始,收款方使用一个 BIP21 URI 来指明转发服务器和自己希望用来接收 payjoin 支付的对称加密密钥。支付方会使用这个密钥来加密自己的交易的一个 PSBT,然后发送给接收者指定的中继。接收者会下载这个 PSBT、解密它,然后给它添加签好名的输入,再发回给中继。支付者下载回传的 PSBT、解密它、确保它是正确的,然后签名并广播到比特币网络中。

    在一个回复中,Adam Gibson 警告了在 BIP21 URI 中包含加密密钥的危险性,以及用户的隐私性风险:中继可以把收款方和发送方的 IP 地址,跟会话结束时相邻时间段内广播到网络中的交易的集合关联起来。Gould 随后修改了这份提案,以尝试解决 Gibson 对加密密钥的顾虑。

    我们期待看到关于这份协议的进一步讨论。

田野调查:实现 MuSig2

第一篇MuSig 论文出版于 2018 年,而且 MuSig 在比特币上的潜能,正是用来让 taproot 软分叉获得支持的卖点之一。对 MuSig 的开发延续了下来,MuSig-DNMuSig2 的论文在 2020 年出版。到 2021 年, taproot 在比特币主网上临近激活的时候,对 MuSig 签名即将到来的兴奋之情是真实可感的。在 BitGo,我们期待能趁着 taproot 的激活发布一款 MuSig taproot 钱包;但是当时的规范、测试节点和参考实现都是不完整的。于是,BitGo 只能先发布第一款基于 tapscript 的多签名钱包,并在主网上发起了第一笔 tapscript 多签名交易。接近两年以后,MuSig2 在 BIP327 中得到规范,我们就发布了第一款 MuSig taproot 多签名钱包。

为什么要使用 MuSig2?

与脚本式多签名相比

相比于脚本式的多签名构造,MuSig 有两大长处。第一点,也是最明显的一点,其交易体积更小(因此矿工手续费更少)。链上的一个签名是 64 ~ 73 字节,换算过来是 16 ~ 18.25 虚拟字节(vB),而 MuSig 可以将两个(甚至更多)签名合并为一个签名。在 BitGo 的 2-of-3 多签名钱包中,使用 MuSig 密钥路径的一个输入只需 57.5 vB,而一个原生的隔离见证输入需要 104.5 vB、使用深度为 1 的脚本路径的 tapscript 输入需要 107.5 vB。第二个好处是,MuSig 也提升了隐私性。在联合持有的输出上使用 MuSig 密钥路径时,这样的合作式花费无法被第三方区块链观察者辨别出跟单签名 taproot 花费有何区别。

当然,MuSig2 也有一些缺点。两种重要的缺点都围绕着签名使用需要用到的 nonce 值。不像普通的 ECDSA(椭圆曲线数字签名算法)和 schnorr 签名,MuSig2 的签名者无法一贯地使用确定性的 nonce 值。这种缺点,使得保证高质量的 nonce 和避免 nonce 复用变得更加困难。MuSig2 在大部分情况下要求 2 轮通信。有些时候,第一轮可以预先计算出来,但必须谨慎进行。

与其它 MPC 协议相比

因为上面提到的手续费和隐私性上的好处,“MPC(多方计算)” 签名协议越来越受欢迎。MuSig 是一种 简单 的多签名协议(只支持 n-of-n 模式),是因为 schnorr 签名的线性可加特性而成为可能的。MuSig2 可以用一场 30 分钟的演讲解释清楚,而完整的参考实现是 461 行的 Python 代码。门限签名(t-of-n)协议,例如 FROST,会复杂很多;甚至基于 ECDSA 的两方的多签名,也要依赖于 Paillier 加密算法和其它技术。

脚本类型的选择

即使在 taproot 激活以前,为一个多签名(t-of-n)钱包选择一种具体的脚本,也是难事。Taproot 因为有了多种花费路径,让这个问题变得更加复杂;而 MuSig 本身甚至提供了更多选项。在我们开始设计 BitGo 的 taproot MuSig2 钱包时,我们考虑了以下事项:

  • 我们使用固定的公钥顺序,而不对公钥使用字典排序。每一个签名密钥都有跟公钥一起储存的特定角色,所以每次都以相同的顺序使用这些公钥会更简单,而且更容易预测。
  • 我们的 MuSig 密钥路径仅包含最常用的签名人组合,“用户”/“bitgo”。将 “后备” 签名密钥包含在 MuSig 密钥路径中,将极大地减少可以使用密钥路径的概率。
  • 我们不在 Taptree(脚本树)上包含 “用户”/“bitgo” 签名组合。这是我们的第二种 taproot 脚本类型;第一种类型包含了 3 个 tapscript 的设计,需要脚本式签名功能的用户可以使用第一种类型。
  • 在 tapscript 中,我们不会使用 MuSig 密钥。我们的钱包包含了一个 “后备” 密钥,这个密钥被假设是难以访问的、而且会使用我们控制之外的软件来签名,所以预期这个后备密钥能够依照 MuSig 协议来签名是不现实的。
  • 在 tapscript 中,我们选择了 OP_CHECKSIG/OP_CHECKSIGVERIFY 而不是 OP_CHECKSIGADD。在构造交易的时候,我们知道哪一把密钥会签名,而 2-of-2 的、深度为 1 的脚本,会比 2-of-3 的、深度为 0 的脚本稍微便宜一些。

所以,最终的结构是这样的:

BitGo's MuSig taproot structure

Nonce(确定性的和随机的)

椭圆曲线数字签名是在一个一次性秘密值(叫做 “nonce”,意思是只用一次的数字)的帮助下制作出来的。通过在签名中分享 nonce 公开值(nonce 公开值和 nonce 秘密值的关系,就像公钥与私钥的关系),验证者可以确认签名等式成立,而无需签名人揭晓自己长期使用的私钥。为了保护这个长期使用的私钥,同一个私钥(或者有关联的私钥)在签名不同的消息时绝不能使用相同的 nonce 值(nonce 不能复用)。对单签名来说,最常被推荐的避免 nonce 复用的方法就是 RFC6979:确定性的 nonce 生成法。完全随机的数值也是安全的,只要它一经使用就立即被丢弃的话。但这些方法都不能直接为多签名协议所用。

为了在 MuSig 中安全地使用确定性 nonce 值,在 MuSig-DN 这样的技术中,必须证明所有的参与者都正确地生成了确定性 nonce 值。没有这样的证据,恶意的签名人就可以为同一条消息发起两个签名会话,然后提供不一样的 nonce 值。另一个生成确定性 nonce 值的签名人会使用相同的 nonce 值为两条实质上不同的信息生成两个碎片签名,最终导致私钥泄露给恶意签名人。

在 MuSig2 规范的开发期间,Dawid 和我意识到,最后一个 贡献 nonce 值的签名人可以确定性地生成自己的 nonce 值。我跟 Jonas Nick 讨论了这一点,他于是将此形式化、成为规范。在 BitGo 的 MuSig2 实现中,这种确定性的签名模式用在了我们 HSM(硬件签名模块)中,以使这些硬件可以无状态地(statelessly)执行 MuSig2 签名。

在多轮签名协议中使用随机 nonce 值时,签名人必须考虑这些 nonce 秘密值在轮次之间如何存储。在单签名中,nonce 秘密值在创建它的同一个执行步骤中就可以删除。如果一个攻击者可以在 nonce 值创建之后、来自其它签名器的 nonce 值到来之前立即克隆一个签名器的状态,这个签名器就可以被诱骗为实质上不同的多条消息使用同一个 nonce 值生成多个签名。因此,我们建议签名人仔细考虑自己的初始状态是否可被访问、nonce 秘密值具体在什么时候会被删除。在 BitGo 用户使用 BitGo SDK 运行 MuSig2 流程时,nonce 秘密值是使用 MuSig-JS 库来保存的,并且,一旦为了签名而访问它们,就会导致它们被删除。

形成规范的流程

我们在 BitGo 实现 MuSig2 的经验表明,在比特币生态里工作的公司和个人应该花时间来审核自己意图实现(甚至只是期待会出现)的东西的规范,并为这样的规范的开发作出贡献。在我们第一次审核 MuSig2 规范的草稿、并开始学习如何最好地将它整合进我们的签名系统时,为了将带状态的签名引入我们的 HSM,我们考虑过许多困难的方法。

幸运的是,在我向 Dawid 介绍了其中的挑战之后,他很确信有一种办法可以使用确定性的 nonce 值,而且我们最终得出了其中一个签名人可以使用确定性 nonce 值的粗糙想法。后来,我又向 Jonas 提起了这个想法,并解释了我们尝试启用的具体应用场景,他意识到了其中的价值,将它融合进了规范。

现在,其它的 MuSig2 实现也可以利用这样的灵活性:其中一位签名人无需管理状态。在开发过程中,通过审核(以及实现)MuSig2 规范的草稿,我们成功为规范作出了贡献,并且在这份规范作为 BIP327 正式发布之后,很快我们的 MuSig2 签名就整装待发了。

MuSig 与 PSBT

PSBT(部分签名的比特币交易) 格式意在携带让各方(比如:签名人和协调人)可以签名一笔交易所需的所有信息。签名所需的信息越多,这种格式的价值就越大。我们试验了 使用额外的字段扩展我们现有的 API 格式以协助 MuSig2 签名 vs. 转化成 PSBT 的成本和好处。最终我们将需要交换的交易数据转化成 PSBT 格式,而且获得了巨大的成功。尚不为许多人所知的是,BitGo 钱包现在可以跟支持 PSBT 的硬件签名设备集成(除了使用 MuSig2 的 BitGo 钱包,详见下一段)。

但现在还没有公开为 MuSig2 签名而设的 PSBT 字段。在我们的实现中,我们基于 Sanket 分享给我们的一份草案,用上了专门的字段。这是一个很少被提起的 PSBT 格式的好处 —— 你可以在同一种二进制格式中额外加入定制化的交易构造或者签名协议所需的 无论什么 数据;因为全局的、每个输入、每个输出的部分已经得到定义。PSBT 规范将未签名的交易跟脚本、签名以及其它最终形成一笔完整的交易所需的数据分离开来。这种分离可以在签名流程中提升通信的效率。举个例子,我们的 HSM 可以拿仅包含自己的 nonce 值和签名的最小 PSBT 作为响应,而这个 PSBT 可以很容易地组合成预签名的 PSBT。

致谢

感谢在 Blockstream 工作的 Jonas Nick 和 Sanket Kanjalkar、在 Fedi 工作的 Dawid Ciężarkiewicz,以及在 BitGo 团队的 Saravanan Mani、David Kaplan,和其他人。

新版本和候选版本

热门的比特币基础设施项目的新版本和候选版本。请考虑升级到新版本,或帮助测试候选版本。

重大的代码和文档变更

本周出现重大变更的有:Bitcoin CoreCore LightningEclairLDKLNDlibsecp256k1Hardware Wallet Interface (HWI)Rust BitcoinBTCPay ServerBDKBitcoin Improvement Proposals (BIPs)Lightning BOLTsBitcoin Inquisition

  • Bitcoin Core #27213 帮助 Bitcoin Core 创建和维护通往更多样的网络中的对等节点的连接,从而减低某些情况下遭遇 “日蚀攻击” 的风险。日蚀攻击指的是,一个节点被不诚实的对等节点包围、完全无法连接到任何一个诚实的对等节点,不诚实的对等节点给他的区块可以跟网络上的其他人看到的都不一样。这种攻击可以用来让受害者节点相信某一笔交易已经得到确认(即使网络上的其他人都不同意),从而欺骗节点运营者已经完成了支付(实际上这些钱他永远花不出去)。提高连接的多样性,可以帮助阻止意外的网络分割 —— 一小部分节点被隔离在网络主流之外,因此无法收到最新区块。

    这个已经合并的 PR 尝试在每一种可以触达的网络中开启至少一个对等连接,而且会防止任意网络上的唯一对等节点被自动断开。

  • Bitcoin Core #28008 添加了加密和解密的惯例,计划用于实现由 BIP324 说明的 “v2 transport protocol”。添加了下列加密算法和类(引用自 PR):

    • “来自 RFC8439 章节 2.8 的 ChaCha20Poly1305 AEAD(带身份的加密法)”

    • “如 BIP324 所定义的【前向保密型】FSChaCha20 流密码,一个围绕 ChaCha20 的密钥轮换(rekeying)封装器”

    • “如 BIP324 所定义的 FSChaCha20Poly1305 AEAD,一个围绕 ChaCha20Poly1305 的密钥轮换封装器”

    • “一个 BIP324Cipher 类,封装了 BIP324 数据包编码所需的密钥协商(key agreement)、密钥派生、流密码,以及 AEAD”

  • LDK #2308 允许支付发送者在自己的支付中包含定制化的 标签-长度-数值(TLV)记录,接收者可以使用 LDK 或者兼容的实现从支付中抽取出来。这可以让使用支付发送定制化数据和元数据变得更容易。