作者:Pavol Rusnak

来源:https://btctranscripts.com/advancing-bitcoin/2022/challenges-in-implementing-coinjoin-in-hardware-wallets

原文为作者在 Advancing Bitcoin 2022 大会上的演讲的转录稿,由 delcin-raj 通过 review.btctranscripts.com 转录。

演讲视频:https://www.youtube.com/watch?v=gqINXwsR33g

引言

各位好,我是 Pavol Rusnak,在比特币社区中人们叫我 Stik 。我是 Satoshi Labs 的联合创始人,我们开发出了 Trezor 硬件签名器。今天我准备聊聊在硬件签名器中签名 CoinJoin 交易的挑战。

为何需要隐私性?

我们先来讲讲隐私性有什么意义。在许许多多的理由中,我认为这些理由是最重要的。

  • 自治:隐私性允许个体控制自己的个人信息,让他们可以作出独立的选择和决定。
  • 人身安全:隐私性保护个体免于跟踪、骚扰和身份盗窃这样的伤害和威胁。
  • 表达自由:隐私性鼓励自由表达和开放沟通。
  • 信任:隐私性是构建个体之间和机构之间的信任的前提。
  • 平等:隐私性有助于每个人得到平等对等,不论其种族、性别、宗教,等等。
  • 民主:隐私性对于保持民主是极为关键的,它让公民可以彼此自由沟通、跟代表自由沟通。
  • 创新:通过为个体和公司提供安全的环境来实验和发展新的理念和技术、无需盗窃和滥用,隐私性鼓励了创新。

总结一下,隐私性是一种基本的人权,保护着个体的自治、人身安全和自由,同时鼓励信任、平等、民主和创新。

比特币中的隐私性

比特币隐私性的现状

在比特币中,交易会被记录在一条公开的区块链上,可以被任何人跟踪和分析,甚至可以溯及既往。交易参与者的真实身份并不必然是已知的,但这些身份常常被多种手段关联起来,比如 IP 地址跟踪、公开的信息泄露。交易跟身份发生关联的例子还包括在 Twitter 或 Nostr 的个人简介里发布接收捐赠的地址 地址;如果当事人还重复使用地址,那更是雪上加霜。但这都比不上交易所和他们对客户的做法危害这么大。

相关的隐私保护技术有哪些?

  • “机密交易” 是其中一种,它会遮掩交易的金额。但我们需要验证在此过程中比特币没有增发(也没有销毁)。通常会部署在侧链上。在比特币基础层上,我们还没有机密交易技术。
  • 闪电网络同样有助于隐私性,因为区块链只展示开启通道和关闭通道的交易,不会展示用户在其中的每一笔交易。
  • 有一些服务,比如 Tor 和私人虚拟网络,可以帮助你隐藏 IP 地址(从而隐藏你的地理位置)。并且将众多交易关联起来会变得更难。比如说,在 Tor 上,你可以在发送不同交易时切换不同身份,那么他们在网络上会被当成不同的人。
  • 当然,CoinJoin 也是其中之一。

CoinJoin

好,那么什么是 “CoinJoin”?它是一种加强隐私性、提高比特币交易匿名性的技术。多个参与者将他们的交易合并在一起(也就是汇集各自的输入和输出),然后签名一笔体积更大的交易。最终的交易让人更难将输入和输出关联到其各自的主人。CoinJoin 可以比我这里展示的规模大得多,不过这个例子也足够形象了。

案例

假设有三个参与者,同意加入同一笔交易,他们有 5 + 3 个输出(多出来的 3 个是因为要考虑找零输出)。假设输入有 3 个。你也许能猜到这些找零输出分别属于哪个人。但其它输出,你就无法断定了。搞不清楚哪个输出是这个人的还是那个人的。这里的关键是,创造出同样面额的输出。而这些同样面额的输出的集群,获得了我们称之为 “k-匿名集” 的东西。在这个案例中,这组输出属于同一个 k-匿名集,k 是 5 。还是那句话,你猜不出来哪个人拥有哪个输出。

一次 CoinJoin 的阶段

  1. 输入登记:每个参与者都在一个协调员处登记自己的输入。这通常是通过 Tor 往里来进行的,每个输入都来自一个 Tor 身份。成功登记输入之后,协调员会给这个参与者一些东西(我称之为 “token”),不过它不是密码货币 token 。它可能是,比如说,在 Wasabi 1中是一个盲签名,在 Wasabi 2 中是一个使用密钥可以验证的匿名证书。我不会再讲更多细节,重点知识,你得到的这个 token 可以用在第二个阶段,也就是输出登记中。
  2. 输出登记:每个参与者都在协调员处登记自己的输出(又要使用另一个 Tor 身份)。这里的重点是因为参与者使用的身份不同于他们在输入登记中使用的身份,所以不会被发现关联。每一次输出登记都要消耗一个 token,它是你有权登记特定大小的一个输出的证据。这个 token 会被 “烧掉”,也就是协调员会将它标记为已经使用。通常,这个 token 也是跟一个 CoinJoin 回合绑定的,不能用在另一个 CoinJoin 回合中。这个设计也很好,因为这个标记清单在本轮 CoinJoin 结束后就可以丢弃,而不会随时间无限增长。在一些技术中,这些 token 是可以无限期使用的,但那通常是各种 e-cash 实现,比如 Cashu 和 Fedimint 。回到 CoinJoin,这些 token 只能用在本回合中。
  3. 签名:在输入和输出都登记完成之后,我们组合出一笔交易、将它发送给每一个参与者,让他们签名。我们可以使用不同的身份,但这不是重点。甚至可以使用在第一阶段中用过的身份,因为只要你在第一阶段登记了输入,就 100% 确定你会在这个阶段签名同一个输入。所有参与者都要提供签名。如果最终组合出来的交易是有效的,那么这次 CoinJoin 就算成功,而这笔交易会被广播到网络中。

在硬件签名器中签名 CoinJoin

现状

那,这关硬件签名器什么事呢? 通常来说,如果你要签名一笔常规交易(不是 CoinJoin),那么硬件签名器会在用户介入下完成签名。这意味着用户会确认输出的地址(也就是输出的脚本);然后确认输出的金额和挖矿手续费(通常就是输入的和减去输出的和)。这里有一个星号,是因为,通常,如果硬件签名器没有检测到极高的手续费,就不会询问用户。我后面还会再讲这一点。

挑战

对 CoinJoin 交易,我们需要在用户不介入的前提下完成交易签名。为什么呢?

因为我们并不知道什么时候其他人准备好了签名、什么时候我们能进入签名阶段。通常来说,我们都需要参与多轮 CoinJoin 才能成功一次。而我们不想让用户坐在电脑前干等(等上两天或者更久)。因此,硬件签名器需要做到多件事。它需要检查输入之和是否等于输出之和再加上一点差额(也就是挖矿手续费、协调员手续费,等等)。困难在于,如何正确地识别哪个输入是我的、哪个输出是我的,以及它们的数额。

隔离见证以前的手续费攻击(伪造输入金额)

输入金额之和减去输出金额之和就是挖矿手续费。但是交易的输入并不包含任何金额信息。它们包含的仅仅是前序交易的哈希值和输出的索引号。所以,如果一个攻击者在输入的金额上撒谎,那会怎么样?比如说,输入的面额是 10 BTC,却被谎称是 1 BTC 。请居住,这是在硬件签名器上,你只能确认输出的面额,不能确认输入的面额。那么这名用户会让 9 BTC 变成交易手续费。

(译者注:作者这里的假设是攻击者篡改了用户的钱包软件 —— 在硬件签名器的语境下,“钱包软件不可信任” 是一种常见的假设。)

Trezor 如何缓解这种攻击

所以,在 Trezor 上,我们总是要传入完整的前序交易,从而,硬件签名器可以计算被花费的输入的真实面额。 这有时候会遇到一点小麻烦 —— 你要花费的交易的体积非常大。并且,我说过了,当手续费非常高的时候,Trezor 会显示一个警告。手续费非常非常高的时候,我们会直接表示出错。只要手续费低于这个门槛,我们就会让它通过。

隔离见证 v0 解决这个问题了吗?

  • BIP-143 的签名也承诺被花费的输入的金额,这是好事。
  • 如果攻击者在 UTXO 数额上撒了谎,那么这个签名直接就是个无效签名,不会被比特币网络认可。

这种解决方案的问题

所以我们这就解决了?并没有。隔离见证 v0 并没有完全修复这个问题。为什么这么说呢?

假设一个受害者有两个 BIP-143(隔离见证 v0)UTXO,面额分别为 15 BTC 和 20 BTC。恶意软件要求用户确认交易, 这笔交易的第一个输入是价值 15 BTC 的 UTXO,而其第二个输入的价值被设定为 5 BTC 加 1 聪;然后用户选择输出和找零输出(如果有必要的话)。于是用户确认了交易。但是 TA 之确认了输出。他们以为自己在花费 20 BTC 加 1 聪。

然后,恶意软件表示出错,让用户再次确认交易。但这一回,恶意软件在第一个输入中使用 1 聪的面额、在第二个输入中使用 20 BTC 的 UTXO;并传给硬件签名器。从用户的角度看,他们看不到交易的输入,只能看到输出。他们以为这跟自己签名的上一笔交易是同一笔。所以用户再次确认花费 20 BTC 加 1 聪。

但是实际上,他们花掉了 15 + 20 BTC,因为恶意软件可以结合这两个签名、创造出一笔把两个 UTXO 都花掉的交易。这意味着 15 BTC 又在不明不白中成了交易手续费。

隔离见证 v1 解决这个问题了吗?

现在,BIP341(Taproot)的签名承诺所有输入的面额。这就很好。所以,交易中的所有签名的承诺所有输入的面额。它们也承诺了输入的脚本。这也很好。这样攻击者就无法修改输入脚本了。那这算是彻底解决了吗?

问题

你怎么看呢?不,还没有。攻击者依然可以在输入脚本上撒谎,说这个输入不属于这个钱包。然后欺骗硬件签名器不要将这个输入考虑在内。然后,你可以执行同样的两次签名、抽取和收集这两个签名、然后结合它们。攻击手法完全一样。

解决办法

这个问题是我的同事 Andrew Kozlik 在 2020 年开发 CoinJoin 签名的时候发现的。他立即提议,BIP341签名应该承诺所有输入的脚本,而不仅仅被签名的这个输入的脚本。幸运的是,讨论发展得很快,所有人都同意应该这样做。没有理由不这样做。所以隔离见证 v1 确实修复了这个问题。隔离见证 v 1 输入的签名承诺了前序交易的哈希值、被花费的输出的索引号、被签名的数额、交易的所有数额、被签名的输入脚本,以及所有的输入脚本。这就是 CoinJoin 真正受益于 Taproot 的地方。

Taproot 与 CoinJoin

让签名承诺所有东西,对于包含外部输入的自动化交易非常好。比如说,在 CoinJoin 中,攻击者无法改变输入的面额和脚本,因为一旦这样做,整个交易都会因为这个错误的签名而作废。

所有权证明

不过,我们要澄清的另外一个事情是,攻击者依然可以扣住一些信息。比如说,一个输入是否属于这个钱包。也许攻击者不想告诉硬件签名器用到的是哪一条 BIP32 路径,而硬件签名器光凭自己也无法搞清楚。然后这个输入就不会进入求值。因此,我们需要某种方式来探明所有输入的所有权。那么该怎么做呢?这对所有带有外部输入的交易都很重要。不仅仅是 CoinJoin 交易,还有双向注资的闪电通道,等等。所以我们需要一种机制,可靠地确定哪个输入是否属于本钱包。该怎么做呢?

SLIP 19 所有权证据

这个叫做 “SLIP 19”。SLIP 对于Satoshi Labs 就像 BIP 对于比特币。SLIP 19 的名称是 “所有权证据”,顾名思义,本质上就是得到签名的三段信息。

  1. 第一段信息是 “所有权标识符”,让我们可以高效地确定本钱包是否可以花费具有给定一个脚本公钥的 UTXO 。这是一种非常简单的构造,基本上就是从种子派生一个对称密钥,然后使用 HMAC(基于哈希函数的消息认证码)来处理这个密钥,将脚本公钥作为它的消息。

HMAC-SHA256(key = 对称密钥; message = 脚本公钥)

  1. 另一段信息是脚本公钥本身。

  2. 我们也有额外的不限定的承诺数据。如果你不想用,也可以不用。但基本上,它就是一个随机的 256 比特的数值;在 CoinJoin 交易中,我们使用 192 比特的 CoinJoin 协调员 ID 以及 64 比特的 CoinJoin 回合 ID 。但它可以是任何数值,只取决于你要开发什么样的应用。

所有东西都会得到签名,通过一种在 BIP322 “通用签名消息格式” 的 2020 年 3 月版本中描述的方法。

为什么人们不大使用 CoinJoin 呢?

  1. 首先,我认为真正的问题是缺乏意识,希望我们能逐步改变这个局面。

    1. 人们不知道 CoinJoin 存在。
    2. 人们完全不理解为什么需要隐私性。
    3. 人们完全不在乎隐私性。我觉得我们生活在一个泡沫里,可能有 99% 的人都不在乎这件事。
  2. 复杂性。我的意思是,可能会有几千种新信息要你在几分钟内处理完,而你都不知道这是在干什么。

  3. 缺乏硬件签名器集成。因为 CoinJoin 钱包通常都是联网钱包,那么你就不想把你所有的聪都放在联网钱包里面。

  4. 最后,并非无足轻重的是,可能有法律上的后果。

结论

所以,我希望 Trezor 和 Wasabi 协调器的集成可以解决上述四个问题,这会在本月晚些时候发布。这就是我的演讲的全部。我们应该还有五分钟来回答一些问题。

问答

【听众】:我知道去年 Adam Gibson 开了一个关于 CoinJoin 的研讨会,他好像还提到另一个问题,就是我们不知道其他参与者是谁。因此,似乎有另一种恐惧是,也许所有其他参与者都来自一个尝试针对你的实体。你怎么看呢?

【Pavol Rusnak】:我认为 Max 也许能够给出一个更加详尽的回答。但我想的是,我们应该努力让 CoinJoin 变得尽可能大。我不知道当前在 Wasabi 协调器那里一次 CoinJoin 的参与者数量上限是多少,我想起码允许 150 个输入。如果只有 5 个输入,那攻击你当然容易得多得多,但如果有 …… 我就是说,希望这个集成会吸引更多人参加 CoinJoin ,而我认为我们可以开始提高限额了。大概就是这样。

【听众】:(无法辨识)比如说,如果我想往交易所充值,他们可以拒绝 CoinJoin 交易的输出吗?

【Pavol Rusnak】:所以,问题在于,交易所跟 CoinJoin 交易的关系是什么、或者说他们怎么看待 CoinJoin 交易?我猜这是他们的问题,不是我的问题。但我认为,不是所有交易所都会采取同样的行为模式。其中有一些会将所有 CoinJoin 输出都标记为非法的,他们不想接受 CoinJoin 交易的输出。我知道还有一些交易所甚至更疯狂,会在你取款之后跟踪你的交易。他们会说你从交易所取款的几天之后似乎参加了 CoinJoin,我们不喜欢你这样做。我认为这就过分了。但我也认为,我们现在做的事情正在为 CoinJoin 吸引更多的用户。以前,交易所很容易贯彻将 CoinJoin 看作非法交易的做法,但是,如果有成千上万个守法的用户都这样做,那么也许他们就会改变做法。如果他们不改变,我猜他们也会遇上问题。所以,这就像是在玩一种博弈游戏,或者四维象棋。

【听众】:嗨,我叫 Robert,我运行了一个 Start9 节点。在法律上为使用 CoinJoin 辩护的最重要理由是什么?他们正在逮捕开发者不是吗?你怎么为之辩护呢?

【Pavol Rusnak】:我怎么辩护?举个例子,捷克共和国有一家非常大的连锁店,出售电子产品。我喜欢用比特币从那家店买电子产品。但我一点也不像告诉他们我有多少聪。但如果我不使用 CoinJoin 的话,这是很容易曝光的,你只需要观察区块链上的交易,马上就能看出这个人买了电子产品。你可以说我已经在这家商店登记了 KYC,因为我会让他们把货发到我的住处。他们可能不会这样做,但只要他们想,他们就能做到。所以我使用 CoinJoin ,基本上就是在钱币 —— 我花费掉的钱币与还在我钱包中的钱币 —— 之间建立防火墙。

(完)