作者:Anony
“静默支付(Silent Payments)” 是一种为实现静态收款标识符同时兼顾隐私性要求而提出的解决方案。使用它,支付接收者只需公开一个稳定不变的标识符(可以视为一种特殊的地址),发送者将在支付发送过程中为接收者创造出不重复的新比特币地址。
本文尝试解释其基本概念、第一个关于静默支付的比特币强化提议 BIP352 [5],并基于 BIP352 的规范展望静默支付的采用方式。
静默支付的基本概念
为理解静默支付的概念,我们先来回顾 “链上” 比特币(也即以区块链为交易确认方式)的支付过程:
- Alice 尝试给 Bob 支付,于是向 Bob 请求一个 Bob 能够使用的比特币脚本(地址是这样的脚本的一种紧凑、防止错误的表现形式 [1]);
- Bob 给 Alice 回复一个地址;
- Alice 将该地址复制到自己的比特币钱包软件中,补充完其它交易细节后广播交易、让交易获得区块链确认;
- Bob 的软件在收到新的区块中,根据 Bob 存储的信息(比如地址)扫描匹配的交易;如果命中,则存储交易的信息,并将相关的交易输出标记为自身可以使用的资金。
此过程跟以下几点有关联:
- 隐私性。如果 Bob 给出的是一个已经使用过的地址,那就会增加该地址被 “去匿名化(deanonymization)” —— 被第三方侦测出该地址的真实主人 —— 的风险。这种损害隐私性的习惯称作 “地址复用”,复用得越多,去匿名化的风险也就越严重。
- 交互性。在上述过程中,Bob 会跟 Alice 交互,给 Alice 提供地址。可以看出,这种交互一定程度上是一种麻烦,但考虑到隐私性,其价值又是显而易见的:Bob 可以借由这种交互的机会,给出新的地址、避免地址复用。
- 备份便利性。只要 Bob 不是在收到支付后立即花掉,就会让比特币在自己的地址中停留,这就产生了备份该地址的密钥信息的需要。考虑到隐私性,Bob 应该为每一笔新支付生成一个新地址,但是如何便利地备份呢?
在当前的比特币保管方案中,BIP-32 分层确定性钱包方案,解决了上述隐私性与备份便利性的矛盾 [2]:Bob 使用的密钥都从同一个种子经过确定的步骤派生出来;由于这些密钥都有同一个源头,因此 Bob 只需备份这个种子即可(最多需要额外备份极少量的派生步骤信息);而由于派生的步骤具有单向性,第三方无法从这些密钥的公钥中推断出他们属于同一个源头,也很好地保证了隐私性。
唯一尚不如人意的地方是,交互需求依然存在。每一个支付者都必须先跟 Bob 建立通信、获得一个新地址,然后才能发起支付。有没有能够实现静态的收款标识符(地址)、又不牺牲隐私性的办法呢?
静默支付概念的提出者 Ruben Somsen 曾在一场演讲中集中地讨论可能的解决方案 [3],静默支付也属于其中之一,而且显示了一种特殊的(可以说有些激进的)取舍:通过增加接收者 Bob 的扫描负担(即上述支付过程第 4 个步骤的复杂性),来消除交互需要。
静默支付运用了一个叫做 “迪菲-赫尔曼 密钥交互(Diffie–Hellman key exchange)” 的概念(它跟 “公钥密码学” 的概念同龄! [4]):如果 Alice 和 Bob 各有一对公私密钥对,那么他们只需知晓对方的公钥,凭借一个简单的操作,就可以获得一个只有他们彼此知晓的共享秘密信息:以己方的私钥乘以对方的公钥。
由于私钥与公钥间的数学关系,当 Alice 拿自己的私钥乘以 Bob 的公钥时,得到的数值会跟 Bob 以自己的私钥乘以 Alice 的公钥得出的结果相同。
我们以基于椭圆曲线的公私钥为例,Alice 的公钥 A 是私钥 a 与椭圆曲线点 G 运行点乘法得到的;Bob 的密钥对类同。那么:
a.B = a*b.G = b*a.G = b.A
。这叫做 “ECDH(椭圆曲线上的 DH 密钥交换)”。根据定义,只有知晓其中一个私钥的人才能获得这个秘密值,所以其他人都不知道,只有他们彼此知道。
设想一下,如果 Bob 提前公开了自己的一个公钥,那么 Alice 无需再与他交互,就可以凭借自己的私钥,得出一个新的秘密值,然后凭此秘密值派生出一个新的公钥(再派生出相应的地址)。比如说,这个新公钥是 Bob 的公钥加上共享秘密值的哈希值的椭圆曲线点:New PK = B + H(a.B).G
;这个公钥背后的私钥是:New sk = b + H(b.A)
。显然,只有 Alice 和 Bob 才能知道这个公钥是如何构造出来的,因为其中用到了只有他们知晓的共享秘密值;而且,只有 Bob 才能花费这个地址里的资金(因为其私钥 b 只有他知道,Alice 也不知道)。
这种办法满足了上述三个要求:(1)只要 Alice 不复用私钥,就不会得到相同的地址;(2)Alice 不再需要跟 Bob 交互,可以直接构造出只有 Bob 能够花费的地址;(3)Bob 也不需要为每一个新地址备份密钥材料,因为从一定意义上来说,它们也都是从同一个种子(密钥对)中派生出来的。
然而,问题是,Alice 怎么告诉 Bob 自己用到了哪一对密钥呢?如果 Bob 不知道 Alice 的公钥,这一套把戏不就没法玩下去了吗?
这就是静默支付与以往的类似概念更激进的地方:它要求 Alice 使用交易输入中用到的公钥,而不用其它手段传达这些信息(比如额外的 OP_RETURN 交易输出),从而,运用了上述密钥交换技巧的交易在外观上跟不使用这类技巧的交易看起来毫无分别!这就最大限度地满足了隐私性的要求,而发掘隐秘信息的任务就完全交给了 Bob。
以上就是静默支付的基本概念。接下来,我们看看 BIP352 如何为上述静默支付的骨架增加血肉、使之成为一种可用的技术,其各项规范又如何影响支付接收者 Bob 的扫描负担。
BIP352:第一个静默支付 BIP
BIP352 编写得很好,在概述部分遵循了逐步推进的流程,详述部分也相当严谨。为平衡介绍其中内容的需要和本文的目的,将其主要设计目的和抉择重述如下:
- 生态兼容性
- BIP352 使用 Bech32m 编码法 [6] 来编码静默支付的收款地址。
- 这一设计使得支持 P2TR 输出的比特币软件无需额外实现新的编解码方法,只需微调就可以从静默支付地址解码出所需的信息。
- 这一设计同样使我们可以定义多种版本的静默支付协议。BIP352 就被定义为 “v0 的静默支付协议”。
- BIP352 使用 Bech32m 编码法 [6] 来编码静默支付的收款地址。
- 保管安全性
- 在 BIP352 静默支付地址中包含的不是一个公钥,而是两个公钥,分别称作 “扫描公钥” 和 “花费公钥”。扫描与自己有关的支付需要知晓 “扫描私钥”,但不需要知道 “花费私钥”。
- 因此使用者可以将花费私钥存储在更安全的设备(比如设计良好的签名器)中。
- 在 BIP352 静默支付地址中包含的不是一个公钥,而是两个公钥,分别称作 “扫描公钥” 和 “花费公钥”。扫描与自己有关的支付需要知晓 “扫描私钥”,但不需要知道 “花费私钥”。
- 隐私性
- 将交易输入的 “输出点(outpoint)” 也加入共享秘密值的推导。输出点是一个 UTXO 的唯一标识符,由创造该 UTXO 的交易的 id 以及该 UTXO 在交易输出间的序号组成。
- 这一设计避免了 Alice(支付发起方)复用 地址/公钥 给 Bob(支付接收方)带来的影响。只要交易 ID 不重合 [7],各 UTXO 的输出点就都是唯一的,即使使用了相同的公钥,派生出来的共享秘密值也将不同,从而不会给 Bob 生成相同的地址。
- 全部输入都参与共享秘密值的推导。取得所有交易输入的输出点中最小的那一个,来推导共享秘密值。并且,Alice 也使用所有符合要求的输入所用的私钥,来推导共享秘密值。
- 这一设计也有助于避免 Bob 辨识出哪个输入来自 Alice。
- 兼容尽可能多的输入类型。BIP352 将 “P2PKH”、“P2WPKH”、“P2SH-P2WPKH” 和 “P2TR” 都定义为符合要求的输入,也即支付者可以拿这些地址类型上的资金来发起静默支付。
- 了解比特币输入类型的读者可以看出,这几乎囊括了所有单公钥控制的标准化脚本。对输入类型的要求越少,也就意味着可能发起静默支付的用户群体规模越大,同时也意味着它跟常规支付的差异越小、越不可能被辨识出来。
- 同时,因为上一点的要求,支付者在构造静默支付的交易时,必须确保自己能让每一个符合要求的交易输入的私钥都能参与共享秘密值的推导。
- 在接收者比特币地址的派生中使用额外的序号,允许支付者在一笔交易中将真实的支付额分散在多个不同的地址中。
- 这可以用来对付基于资金数额的猜测。
- 将交易输入的 “输出点(outpoint)” 也加入共享秘密值的推导。输出点是一个 UTXO 的唯一标识符,由创造该 UTXO 的交易的 id 以及该 UTXO 在交易输出间的序号组成。
- 扫描便利性/管理便利性
- 上述 “使用全部输入” 的设计也便于 Bob 扫描支付。
- 仅允许为 Bob 安排 P2TR 输出。
- 允许 Bob 使用同一组扫描密钥和花费密钥生成多个静默支付地址,办法是通过额外的标签生成多个花费公钥。
- Bob 无需额外的备份,就可以生成多个静默支付地址、为不同的 支付方/支付目的 安排不同的地址。
以上即是 BIP352 的大致内容。
基于上述设计,支付接收者 Bob 在区块链上扫描与自己有关的静默支付交易时的流程大致如下:
- 首先,Bob 要先找出一个区块中潜在的静默支付交易(在 BIP352 中被称为 “eligible transaction”);
- 潜在交易的判断标准有三个:(1)具备 P2TR 输出;(2)包含至少一个上述允许使用类型的输入;(3)不得包含比隔离见证 v1 更高版本的输入。在这里,只有第一个标准的应用仅需交易本身的信息;后面两个标准都要求我们获得输入的前序输出的脚本公钥,才能执行判断,而这种信息是隐式的,并不会在交易中体现出来。
- 而后,Bob 需要遍历一笔潜在交易的所有输入,一方面要找出最小的输出点,另一方面要从上述可使用类型的输入中提取出公钥并加总起来;
- 这一过程会得出共享秘密值推导所需的两个关键信息,一个是包含了最小输出点信息的哈希值,在 BIP352 中叫做 “input_hash”;另一个则是所有合格输入的公钥之和,在 BIP352 中记作 “A”。
- 最后,Bob 要运用 input_hash、A 和自己的扫描私钥派生出共享秘密值,再根据自己的花费公钥派生出一个公钥和对应的 P2TR 脚本;然后检查该交易的输出中存不存在这样的 P2TR 输出,如果有,则将这样的交易和输出保存下来,标记为自己可以花费的资金,如果没有,则表明该交易与自己不相关。
敏锐的读者可以发现,上述 1 和 2 两个步骤,正是BIP352 在 “静默支付” 的基础概念上做出的两个关键设计的直接后果:(1)在派生支付发送方和接收方的共享秘密值时,使用全部交易输入的信息;(2)尽可能支持多种输入类型。这样的扫描负担,显然会影响静默支付的采用(或者说,这种成本会限制其应用场景)。
接下来,我们讨论 BIP352 静默支付钱包可能的工作模式,并使用比较法来理解其扫描负担。
两种工作模式和扫描负担
分析上述接收者扫描流程可以发现:不论扫描者是 Bob 还是 Carol,他们都要运行扫描的前两个步骤,并且在两个步骤结束时得到的结果是相同的。也就是说,因为 BIP352 静默支付 “使用所有输入”,所以,一笔交易是否是潜在静默支付交易,以及(如果是)其 input_hash 和 A,是一种对所有静默支付接收者都同样有用的信息,一种可以复用的信息(实际上,接收者只需要获得这两者的乘积)。由此,可以想象的一种工作模式是 “服务端-客户端 模式” :由服务端运行扫描的前两个步骤,并给客户端提供得到的结果;客户端仅根据本地的密钥信息运行最后一个步骤。这种模式就类似于常规钱包中的 “全节点-轻节点” 模式,可以大大减少客户端的工作量。
与之相对的是 “集成模式”,即不分拆工作量,三个步骤都由同一台计算机完成。
然而,更细致地考虑上述扫描步骤,并联系起全节点的工作模式,你会有更进一步的发现:
扫描步骤 1 和 2 需要获得一笔交易的所有输入的脚本公钥,用于判断输入的脚本类型,并根据脚本的类型执行相应的公钥提取步骤,仅凭暴露在交易中的信息,包括 “脚本签名(ScriptSig)” 和 “见证(txinwitness)”,是不够的。然而,全节点在验证新到达的区块中的交易时,本身也要求这些信息,并且,获得这些信息仅需要在 UTXO 集中搜索,不需要访问历史区块和历史交易(不触发较深的硬盘读取)。
也就是说,如果在验证新区块内交易的同时执行上述扫描步骤,那就是顺带的,额外开销完全来自于计算(输入输出的类型检查、公钥提取、共享秘密值推导、ECDH,等),客观来说这些计算量也不会太大;然而,如果我们使用一个单独的进程来运行扫描,则不仅要付出额外的计算开销,还需要额外的、较深的硬盘读取,因为新区块一旦验证完成,其中的交易的输入的脚本公钥就不再能从 UTXO 集中获得,只能通过访问历史交易来获得(并且,这里还多一项存储空间开销:为区块链上的所有交易编制索引,如果这样的索引不存在,则实际上无法读取历史交易,而同步 验证-扫描 模式并不需要为历史交易编制索引)。
由于这种显著的开销区别 [8],我们补充 “集成模式” 的定义:扫描步骤作为区块验证的附属步骤,与区块验证同步完成。
请注意,补充完定义之后,“集成模式” 和 “服务端-客户端 模式” 的合集就不构成全集:有一种可能是,不分拆扫描的工作量,但扫描工作依然在一个独立的进程中完成。
构造这两种模式的定义仅仅是为了便于我们通过比较来理解 BIP352 静默支付接收者的扫描负担:由于定义的准确性,他们都有合适的比较对象,集成模式可以跟基于全节点的常规钱包作比较;服务端-客户端 模式可以跟基于 BIP158 区块过滤器 [9] 的轻节点的常规钱包作比较。
为此,我们对网络中出现的交易的数量与比例,以及钱包所控制的地址的数量,作出以下假设:
- 平均每个区块包含
n
笔交易,它们总共有m
个交易输入和o
个交易输出; - 至少包含一个 P2TR 输出的交易占比为
p
,而 P2TR 输出占单区块内所有输出的比例为q
; - 静默支付钱包仅公开
1
个静默支付地址; - 常规钱包包含
20
个 P2TR 地址; - 仅考虑交易输出中出现本钱包地址的情形(接收支付的情形)。
在上述假设下,基于全节点的常规钱包的扫描负担是:20 * o * q
,也即对区块中每一个 P2TR 输出运行 20 次地址匹配检查。而集成模式中的静默支付钱包的扫描负担是:n * p * I + o * q * 1
,第一项是静默支付扫描的前两个步骤带来的开销,它是以交易为单位的,这里的 I
是对一笔交易执行类型检查、公钥提取、ECDH 等操作所需的计算量,这里假设是一个常数;第二项则是对这些潜在交易的每一个 P2TR 输出执行地址匹配检查所需的计算量,给定钱包主人只公开过 1
个静默支付地址,就只需要执行 1
次。
至于基于轻节点的常规钱包,我们知道其工作模式是先验证区块过滤器;如果过滤器显示区块内没有自己关心的输入和输出,则不再下载完整的区块;如果区块过滤器显示有(这里存在一个极小的误判可能),则下载并检查地址匹配。我们把验证区块过滤器的负担当成一个常数(这不影响比较),则其扫描负担是:1/x * 20 * o * q
,这里的 1/x
就是过滤器命中的概率,该值必定大于 BIP158 区块过滤器的误判概率,但实际大小取决于本钱包收取的交易在区块间的分布。
而基于 服务端-客户端 模式的静默支付钱包,其扫描负担是:n * p * I_1 + o * q * 1
。这个式子之所以跟集成模式这么相似,是因为:服务端仅仅只是完成了一部分扫描工作,而对每一笔可能的交易,客户端都仍需执行一部分工作(具体来说是 ECDH)(它只是 I
的一部分,因此记为 I_1
),而对 P2TR 输出的地址匹配检查,则完全无法从服务端的工作中受益,因此保持原样。
总结上面的分析:
- 常规钱包的扫描负担很大程度上是由同类型输出的数量决定的,但静默支付钱包的扫描负担则有一部分(甚至是主要的部分)跟合格交易的数量有关,两者不便于直接对比;但从计算复杂性的角度看,静默支付的扫描负担绝大概率是更大的。具体来说,这种负担跟包含 P2TR 输出的交易的占比有关;占比越大,静默支付钱包的扫描负担越大;
- 常规钱包和静默支付钱包都可以从转向 轻节点/客户端 模式获得显著的好处;
- 静默支付钱包与常规钱包的扫描负担的差异在客户端模式下会更大,也即更容易让用户感受出性能差异。静默支付钱包可能更适合稳定的桌面端,而非日常使用的移动端。
静默支付的现在和未来
性能/成本 毫无疑问会影响一项技术的采用。从上述分析中我们可以知道,不论在哪一种工作模式下,静默支付钱包都要付出相对常规钱包更大的代价。可以说这也在我们的意料之中,因为这是 “静默支付” 的先天特性。至少,在人们设想的应用场景(接受捐赠、以机构身份接受支付)中,静态收款方式的好处应该能盖过其额外开销。而且,给定 服务端-客户端 的可能性,一部分工作量是可以复用的。
当前,多个项目在尝试实现 BIP352 静默支付钱包,比如:
- 在 Bitcoin Core 中实现 BIP352:https://github.com/bitcoin/bitcoin/issues/28536
- Dana Wallet 移动端静默支付钱包:https://github.com/cygnet3/danawallet
此外,开发者们也正在为了让静默支付能够兼容 coinjoin 交易而增加多种规范。在 coinjoin 交易中,多个参与者会各自为交易提供输入并指定输出;根据 BIP352,为了让这样的交易承载静默支付,支付者必须让每一个合格输入的私钥都参与共享秘密值的推导;同时,这不能造成真实私钥的泄露;此外,还需要工具能够在各方之间传递被构造的交易的信息(接收者的脚本必须在每一个参与者都参与计算之后才能得出)。与此相关的规范有:
- BIP374 离散对数等式证据:https://github.com/bitcoin/bips/pull/1689
- 离散对数等式证据可以让私钥持有者证明自己知道一个私钥而不暴露这个私钥是什么。
- BIP375 使用 PSBT 发送静默支付:https://github.com/bitcoin/bips/blob/master/bip-0375.mediawiki
- 定义可在多方签名的静默支付交易协作中传递信息的 “PSBT(待签名的比特币交易)” 数据格式。
人们还在探索与静默支付有关的协议设计空间。
(完)
脚注
1. https://www.btcstudy.org/2024/11/22/bitcoin-address-types-its-essentials-and-its-economics/ ↩
2. https://www.btcstudy.org/2023/10/25/a-guide-for-recovering-your-bitcoin-wallets/ ↩
3. https://www.btcstudy.org/2022/10/19/on-various-non-interactive-payments/ ↩
4. https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange ↩
5. https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki ↩
6. https://www.btcstudy.org/2024/11/22/bitcoin-address-types-its-essentials-and-its-economics/#Bech32m ↩
7. https://www.btcstudy.org/2024/04/17/transaction-security-improvement-from-soft-forks/#BIP30%EF%BC%9A%E7%A6%81%E6%AD%A2%E5%87%BA%E7%8E%B0%E7%9B%B8%E5%90%8C%E7%9A%84%E4%BA%A4%E6%98%93-ID ↩
8. 这种显著的开销差异可能解释了为何一些开发者决心在 Bitcoin Core 中实现 BIP352。见:https://github.com/bitcoin/bitcoin/issues/28536 ↩
9. https://www.btcstudy.org/2022/04/18/how-neutrino-works-by-Suredbits/ ↩