文章讨论了比特币 Payjoin 的隐私脆弱点:钱包软件在输入选择、找零、手续费、签名编码等细节上的差异会形成“钱包指纹”,分析者可借此区分交易参与方并重建输入/输出归属。文中通过三个真实案例说明,低 r/高 r 签名、Taproot 签名是否显式携带 sighash、nSequence 取值等细节,都可能在单笔交易内或跨交易中暴露发送者与接收者身份,进而削弱 Payjoin 用于打破链上聚类分析的隐私保护效果。
作者:Armin Sabouri
来源: https://payjoin.org/blog/2026/03/25/wallet-fingerprints-payjoin-privacy/
钱包软件在构造一笔交易的时候,会作出数十个微小的决策:输入的排序、钱币的挑选、手续费估计,还有签名编码;等等。这些决策所形成的模式,叫做 “钱包指纹”,在不同的软件实现之间有系统性的不同,因此可以用来识别制作区块链上交易的源头钱包软件。
一些指纹是确定性的。比如,Bitcoin Core 在生成 ECDSA 签名时,会不断尝试不同的随机数(“研磨”),以使最终得到的签名具有 “低 r 值”(这样的签名的字节数会少一些),因此, 只要一个签名是 72 字节长的,就可以立即排除使用 Bitcoin Core 作为签名器的可能。有一些指纹则是概率性的:各钱包软件给出的手续费率会有一些典型的分布。Bug 也会成为指纹。每一个维护都会提供独立的证据,这些证据复合起来会变得非常有利。Ishaana Misra 曾经作过 钱包指纹的综合性研究( 中文译本)。
指纹可以增强钱包聚类分析的效果 —— 聚类分析指的是使用行为线索来归集有关联的交易输出(钱币)。有关聚类分析的背景知识,请看 Yuval Kogman 的 讲述钱包聚类分析历史 的博文( 中文译本)。最近,关于使用钱包指纹来支撑已有的线索分析(比如 找零输出识别)的工作,证明了可以在粗糙的启发式分析之上获得巨大提升。 Kappos 等人 证明了,结合来自临近交易的指纹与数值分析,可以提升聚类分析的准确性;这是用真实场景中的数据验证了这种方法的可行性。这就直接威胁到了 payjoin 交易的隐私性模型:它的基础是无法甄别支付发送方和接收方的输入。能够区分输入来源的钱包指纹,带回了 payjoin 尝试打破的聚类分析。
(译者注:“heuristics” 在本文中译为 “线索分析” 或 “启发式分析”。)
本文就使用这一视角来观察真实的 payjoin 交易。
理论上,Payjoin 交易跟标准的单方交易看起来没有分别。分析者如果使用传统的启发式分析,就会错误地归类这些交易、将发送者和接收者的输入(钱币)都划分到同一个集群。所以,要感知 payjoin 交易,第一步就是侦测出合作式交易的人工痕迹。
Simin Ghesmati 等人 的工作证明了,挑选输入时候的怪癖(具体来说是安排多余的输入)如何能用于侦测 payjoin 交易、以及区分输入和输出的主人。钱包指纹就是在相同的任务上提供了另一种信号。
如果发送者和接收者使用了不同的钱包软件,指纹就可能会揭晓哪个输入和输出属于谁。一旦你推断出所有权的区别,标准的 “输入所有权同一性(CIOH)” 聚类方法就能应用在各个参与者的输入上,从而,从分析的角度看,payjoin 就等同于一对常规(单方支付)交易。
钱包指纹信号在两个层面上释放了信息:
因此,针对一笔 payjoin 交易的区块链分析的目标是:
交易: 8dba6657...
观察这笔交易的各个字段的值,看不出任何可疑的地方。两个输入的 nSequence(字段的数值)是相同的,也都使用 P2WPKH 脚本公钥类型,它们的见证数据堆栈看起来也相似。信号来自签名的长度(字节数)。
0 号输入的 DER 编码的(ECDSA)签名是 71 字节(它是低 r 的);1 号输入的签名是 72 字节(它是高 r 的)。一个会研磨的钱包软件只会产生低 r 签名;不研磨的钱包软件则只有 50% 的概率产生低 r 签名。所以,在一笔交易内出现了一对 低 r/高 r 签名,还不是合作的强力证据。不过,如果其中一个输入来自一个总是研磨的集群,这次却跟 高 r 输入一起出现,它们分属两个钱包集群的概率就更大了。
将签名的不对称性作为候选的区隔一句:参与者 A 持有低 r 输入,参与者 B 持有高 r 输入;前者的面额是 5 0000 聪,后者是 399 9216 聪。我们可以测试输出的两种可能情形:
情形 1:0 号输出(9752 聪)属于 A,1 号输出(403 9216 聪)属于 B 。
情形 2:0 号输出(9752 聪)属于 B,1 号输出(403 9216 聪)属于 A 。
情形 1 意味着支付的数额恰好是 4 万聪;情形 2 则意味着是 398 9216 聪。 整数启发式分析 倾向于情形 1 。后来的花费交易巩固了这个结论: 0 号输出 也被一个低 r 签名花费(与本交易中 A 的输入一致); 1 号输出 也被一个高 r 签名花费(与本交易中 B 的输入一致)。
Payjoin 就这样被瓦解了:输入/输出 的所有权区别被推断出来了,支付的数额也被找出来了。
交易: 3c5436f1...
两个输入都采用 P2TR 密钥路径花费。根据 P2TR 上的 Taproot 花费规则,默认的 sighash 标签是 SIGHASH_ALL,然后这个 sighash 字节就可以省略掉。省略它是正统的形式,但不省略它在共识上也是有效的。0 号输入的见证数据是 64 字节 —— 它省去了 sighash 字节。但 1 号输入的见证数据是 65 字节 —— 出现了 0x01(显式表示 SIGHASH_ALL 的字节)。出现这个字节通常是一个实现上的 bug ,而不是有意为之。
两个输入如果来自同一个钱包(使用相同的钱包软件),应该会使用一致的 sighash 策略。这种不一致,将这两个输入区别开来:参与者 A 持有这个省去 sighash 字节的输入;参与者 B 持有这个带有显式 sighash 字节的输出。
与案例 1 不同的是,在这个案例中,数值线索并不能区分输出的主人。两种归属情形在含义上一样:
情形 1:0 号输出(5 9014 聪)属于 A,1 号输出(86 4506 聪)属于 B 。
情形 2:0 号输出(5 9014 聪)属于 B,1 号输出(86 4506 聪)属于 A 。
整数线索倾向于情形 1,但这种办法也不是万无一失。我们有很大的把握,这是一笔多方构造的交易,因为存在钱包指纹信号;但是,所有权区别则无法肯定。Sighash 处理方式的不一致是一个残留的漏洞,但也就到此为止。
不过,后来,第二个输出的 花费交易 再次出现了显式表示 SIGHASH_ALL 的字节,与本交易中的第二个输入一致。这强烈表明,第二个输出跟第二个输入属于同一个交易,所以情形 1 是更有可能的。
交易: 8fb80573...
首先映入眼帘的是,两个输入的 nSequence 字段的值都是 0x01。Cake Wallet 根据 BIP-68 设置了一个相对时间锁,而 Bull Bitcoim Mobile 也匹配了这个数值,所以两个输入不存在交易内部的不对称性。签名也是同质的:两个输入都使用了低 r 签名,并且使用了相同的 sighash 标签。单单从这笔交易看,指纹分析卡住了。
但是,金额归属,提供了一种可能的区隔。两种情形如下:
情形 1:0 号输出(2 9358 聪)属于 B,1 号输出(42 9919 聪)属于 A。
情形 2:0 号输出(2 9358 聪)属于 A,1 号输出(42 9919 聪)属于 B 。
支付面额整数假设压倒性倾向于情形 1 。此外,接收者的输入(1 9358 聪)小于发送者的找零(42 9919 聪),这跟 UIH2 (多余输入)假设一致:发送者没有合适面额的钱币,因此只好提供一个大额输入并创建一个大额找零,同时,接收方的钱币是恰好能覆盖支付数额的。一种可能的区隔是:0 号输出(2 9358 聪)是支付,1 号输入(1 9358 聪)是收款方的 UTXO,1 号输出(42 9919 聪)是发送者的找零。
跨交易分析也支持这种结论。 0 号输入 的前序交易有一个输入的 nSequence 数值是 0x01,但另一个输入的 nSequence 数值是 0xfffffffd。这种不对称让该交易的输入有了区别,使我们知道它的面值为 44 0337 的输出属于使用 nSequence 数值为 0x01 的参与者;这个输出作为 0 号输入,进入了我们视察的这笔 payjoin 交易。
而 1 号输入 的前序交易的所有输出都只使用 0xfffffffd 作为 nSequence 数值。此外, 花费 1 号输出 的交易也将nSequence 数值设为 0xfffffffd。这跟 Bull Bitcoin Mobile 的典型动作一致,因此是 1 号输出及 1 号输入属于同一个钱包的有力证据。
┌──────────────────────────┐
│ PRIOR TX (9ecd77...) │
│ │
│ in_0 [seq=1] │
│ in_1 [seq=MAX-2] │
│ ──────────────────────── │
│ out_0: 204,326 │
│ out_1: 440,337 ──────────────────┐
└──────────────────────────┘ │
│ ┌──────────────────────────┐
│ │ PAYJOIN TX (8fb805...) │
│ │ ──────────────────────── │
└──►│ in_0 [seq=1] │
┌──►│ in_1 [seq=1] │
┌──────────────────────────┐ │ │ ──────────────────────── │
│ PRIOR TX (3fbe17...) │ │ │ out_0: 29,358 │
│ │ │ │ out_1: 429,919 ──────────────────┐
│ in_0 [seq=MAX-2] │ │ └──────────────────────────┘ │
│ in_1 [seq=MAX-2] │ │ │
│ ──────────────────────── │ │ │
│ out_0: 430,856 │ │ ┌──────────────────────────┐ │
│ out_1: 19,358 ──────────────────┘ │ SUBSEQUENT TX (9232d5...)│ │
└──────────────────────────┘ │ ──────────────────────── │ │
│ in_0 [seq=MAX-2] ◄───────────────┘
│ ... │
└──────────────────────────┘
两个输入的指纹都在交易图谱中持久存在。Cake 的 0x01 可以追溯到前序交易,Bull Bitcoin Mobile 的 0xfffffffd 可以前向追溯,也可以后向追溯。单从这一笔 payjoin 交易可能看不出什么,一旦视察相邻交易,就会变得清楚。
这些观察告诉我们,payjoin 的隐私保护效果,只有在参与者的钱包的指纹都同质化的前提下,才能保存。交易层面的指纹同质性是必要的,但还不够。发送者和接收者在任何维度上的差异,都可能成为一种区分他们的信号。分析者的工作简化成了在钱包动作中找出这些差异,而交易图提供了不定数量的观测值,让分析者可以找到它们。
虽然一些钱包指纹 相对容易消除,还有一些指纹内生于该钱包的一些具体的设计抉择和目标,无法简单 “修复”。在集成 payjoin 到自己的软件时,钱包开发者应该意识到潜在的隐私性泄露。
本文中的分析进关注单笔 payjoin 交易,但方法可以普遍化。钱包指纹的分布可以成为集群的一个属性,具有一致指纹的一个集群,比内部存在不兼容特征的集群更加可信。这指出了对 payjoin 隐私性的一类广泛的攻击。未来的工作将形成一套自动化的大规模分析,使用指纹分布来给集群的可信度评分。我们正在开发这样的工具,作为我们的 隐私性指标框架 的一部分。
(完)
- 本文转载自: btcstudy.org/2026/04/21/... , 如有侵权请联系管理员删除。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!