作者:AdamISZ
来源:https://reyify.com/blog/lightning-unchained/
原文发表于 2025 年 2 月。
闪电网络有一个问题,在工程师之间算得上人尽皆知,但可能用户和钱包开发者们很少思考过(没准大家都想过,真希望我是错的!),那就是,闪电网络的用户不得不公开自己用来开设通道的 UTXO 。设想如果可以不这样做,作为一名用户,你的隐私性可以好多少。
闪电网络的链上软肋
为了解释清楚,我要先岔开以下话题,还要介绍闪电网络工作原理的一个重要方面。就从一个叫做 short-channel-id(通道短 ID)的东西开始。
“通道短 ID” 是编码了一个 UTXO 的 8 字节字符串。在比特币协议内,一个 UTXO 可以用一个元组 (outpoint, index) 来指代,其中的 “输出点(outpoint)” 是创造这个 UTXO 的交易的标识符(txid),而 “索引号(index)” 则是这个 UTXO 在该交易的输出中的位置。这种方法虽然不会产生歧义,却使用了 36 个字节(32 + 4 ;虽然用 4 个字节来表示一个索引号有点大材小用,但木已成舟)。稍后我们会明白,闪电网络协议的设计者们专门创建了一种更高效的编码方式(只使用 8 个字节,不需要 36 个字节)。要是你想知道为什么只需要 8 个字节,就想想,为了指明一个 UTXO ,你只需要指明哪些东西:一个(它在其中创建出来的)区块号、一个交易编号(因为区块包含的是 有序的 交易列表),最后是这个交易的一个输出。这三个整数,每一个都有最大数值,所以你可以对每一个整数使用合理的编码(分别用到 3 个、3 个、2 个字节)。
这样做有啥意思呢?来,我们再回想一下。“闪电网络”,我常常说,有两部分。第一部分是 “闪电(通道)”,意味着两方之间的 Poon-Dryja 式支付通道;第二部分是 “网络”,意味着在多条首尾连接的通道(货币通路)中强制执行的哈希时间锁合约(HTLC)。这里的第二部分 —— “网络” —— 就是关键。为了构造通路,你需要先知道这些通道存在(甚至还有更难的,你必须知道或者猜测这些通道内、在你需要的方向上,有多少余额可用!)。为 此 ,你必须让别人告诉你它们存在。这就是为什么我们要有 “闪电网络 gossip 协议”,这些消息中的绝大部分,都是在告诉对等节点:某些通道存在。
那么问题来了:在一个互不信任的环境中,人们可能会说谎 —— 我完全可以胡说八道嘛。我发现了 10000 条通道,每条通道都有 1 BTC 的容量,这里是一份完整的名单,你自个儿找去吧 …… 这完全可以用来浪费你的时间、让你的 CPU 做无用功;而且,最后,你可能会得到一个全然无用的通道图景,每当你对照这个图来尝试在 “网络” 中转发金钱,结果总是失败。
所以,我们用上了通道短 ID;如前所述,它是 UTXO 的紧凑表示方式。UTXO 并不能免费创建,虽然创建一个是非常便宜的(在区块链内手续费率极低的时候,只需要 1 ~ 2 聪/vB 的费率就能发送交易、创建 UTXO,按照今天的汇率,大概是 10 ~ 30 美分),但代价会随着创建的数量线性增长;而且,如果你想要 很快地 创造出 10 万个 UTXO,代价甚至可能是无穷大的。
我认为,这是一个鲜有人讨论、但非常重要的点:由比特币的极高哈希率,为 UTXO 的创生速度(每秒可创造的 UTXO 输出)带来的天然刹车,让 UTXO 的创造成本不仅不是线性的,还几乎有个爆炸点(singularity) —— 这正是你在搭建公开服务时所需要的良好抗 DoS 措施.
现在可以回答问题了:需要紧凑地编码 UTXO, 是因为这些编码需要广播。如果有 1 万条甚至 10 万条通道,那就有一大堆需要传播的 UTXO 数据,要是每一个都需要 36 字节,那情形就会比现状(使用通道短 ID )糟糕得多。
问题的细节
问题用一个词就能说清楚:隐私型。向整个网络宣布你持有哪些 UTXO,就意味着向全世界宣布 —— 尤其是,你通过一个公开的、明文的 IPv4/6 网络地址来发送宣布消息(许多 “严肃的” 节点都这么干哦);这简直是邀请间谍来分析你在区块链内的活动。这可能不会变成商业风险,但 绝对 是一种安全风险。这些信息可以跟其它信息交叉关联起来,比如,连接到你的 IP 地址、开始打探你是谁、你住在哪里、你持有多少比特币,等等。
基本上,这就是 P2P 网络典型冲突的又一次显现。什么 “典型冲突”?很简单:
在开放的点对点网络中,保护资源要求我们抵御分身攻击(Sybil attacks),这跟用户希望匿名的安全性要求相冲突
(译者注:“Sybil attacks” 指的是攻击者可以轻易伪造出许多身份来消耗受害者的资源;旧译为直译 “女巫攻击”。)
如果说这种 “典型冲突” 有什么 “典型解决方案”,从我的角度看,那就是要求用户使用一种稀缺资源来参与点对点网络。(另一种 “解决方案” 是强制要求非匿名性,但这是一种脆弱的方法,时间一长总会失败。 —— 这是我个人的观点,但正因为纯粹是个人观点,所以但说无妨。)
这种冲突和解决,在最近 Tor 洋葱网络的服务故障中也上演了 —— 分身消耗了大量资源,而解决方法是工作量证明。基于计算循环的工作量证明是不是真的能解决这个问题,我改天再讨论,因为我想回到闪电网络 gossip 的问题!
好了,通道短 ID 会直接揭晓 UTXO 。我们已经知道这是坏事了。那我们能做什么呢?至少我们可以尝试这样做:
我有一条通道。我准备证明,我用来开启通道的 UTXO 的价值是 X 聪(或者至少有 X 聪),但我一点也不想告诉你们哪一条拥有这么多聪的通道是我的。
这个想法,首先,很吸引人,但听起来也疯疯癫癫的 —— 如果你不是 “零知识证明(ZKP)” 的爱好者的话。在深入了解 ZKP 之前,我们先要解决一个非常讨巧的逻辑问题:
一个 UTXO 是否真的被用来开启一条通道,这个事实会是一个公开知识吗?在当前使用 P2WSH 输出来开启通道的情形中,从技术上来说,即使到关闭的时候,也不会揭晓这样的事实,尽管有明显的信号(闪电网络的工程师们请大胆纠正我)。至于 taproot 通道,至少在 MuSig2 发展起来之后,我们可以指望或者说预期,通道们将永远不会暴露它们是 2-2 多签名的,更不用说它是一条通道了。提醒一下,这场讨论是关于施加成本来防止 DOS 攻击的,所以我要断言,尝试证明 “这是一条通道” 是一个错误的方向。只需证明 UTXO 所有权就够了。
(不同意?没问题,我们想得再仔细一些。我声称存在一条通道,我公开它(或者说 gossip 它)。为了支持我的声明,我给出一个通道短 ID;这个通道短 ID 指向区块链内的一个真实的 UTXO ,但你怎么知道这个 UTXO 真的指向一条通道呢?如果我就是要说谎,我只需要让这个 UTXO “看起来像是一条通道”。如我们前面所说的,在有些情况下,所有的 UTXO 看起来都会像通道(使用 taproot 输出、MuSig2 得到广泛采用)。甚至,作为一个攻击者,我可以 真的制作出一条真实的通道,然后让它完全不工作而不违反协议要求。在 gossip 消息中使用通道短 ID 来 “证明一条通道” 的最终意义,只是 “证明我创造了一个 UTXO”。)
但我们还可以讨论得更细一些。你想要让谁承担代价、让什么样的行为承担代价?在这篇旧文章中,Rusty Russel 提议在节点层面施加成本,而不是在通道层面。不论其中的技术难度(对此我可以说几乎一无所知),我同意这种视角的主要原因在于,解除代价与对你有益的资源的关联,可以进一步提高各通道的实际隐私性(例如,假设你创建了一条容量非常大的通道,然后立即发布一个零知识证据来证明它存在,而这个证据意味着 “我证明我拥有一条通道,它的容量至少是 2 BTC”,可是刚好就有一个价值 2.2 BTC 的 UTXO 出现在链上;这只是一个例子,你应该能理解我的意思)。
但是这还不是故事的结局:“到底是,还是不是通道 UTXO?” 想必你可以在本博客的评论区了解更多。
好,我承认你说的它的用处,但这能够实现吗?用 ZKP 之类的东西?
所以,到底有没有可能呢?总结上文,我们要证明的是:
当前存在的、面额在一定范围内的 UTXO 中,有一个是我的;我们可以假设是 taproot 通道,但并不限制 “通道的类型”(理想情况下你甚至不会知道它的类型);但我不会告诉你到底是哪一个
可是在合理的数值范围,可能有几十万到几千万个 UTXO 。这能做到吗?显然不是那么简单。
我研究这个问题 3 年了,反反复复(虽然,我要澄清,我并不是只关注闪电网络,我关注的是广义的隐私型抗分身方案)。最早,我关注的是 “环签名(ring signatures)”,我意识到, 这样的构造存在,但(证据的) 体积 可能是 O(log N)(以字节计)。问题在于,证据的验证和计算时间都是 O(N) 。Bulletproofs 也有这个问题。没有这个问题是默克尔树 —— 这是 Andrew Poelstra 给我的一个洞见 —— 默克尔证据的验证时间是 O(log N) ;大约是同一时间(2022),“曲线树(Curve Trees)” 出现了,它实现了两者的组合:你可以使用 bulletproofs 来生成紧凑的证据,然后用一种代数版本的默克尔树(使用极其特殊的 secp-secq 曲线循环)来实现验证的对数扩容。务实的结果是,对于 100 万个 UTXO 所组成的集合,你可以在 50 到 100 毫秒内验证证据(使用我的代码就可以做到,而且应该能做得更好!),可以用 1 ~ 2 秒来生成一个证据,证据的体积在 2 到 3 kB 之间。再提醒一次,这些证据证明的是 “我持有这 100 万个 UTXO 的其中之一,但我不会告诉你到底是哪一个 ”。要了解同一想法的一个更加完备的版本,可见 FCMP++ 项目,虽然那是 Monero 区块链上的。
最近,J T Halseth 发布了 output-zero ,它是解决同一个问题的迥然有别的办法。它用到了另一种 ZKP,具体来说是 zkSTARKs,不是 Bulletproofs(实现的细节见 risc0),然后使用了一个 Groth16 封装器来创造紧凑的证据。
如果你感兴趣,我强烈建议你看看 Delving Bitcoin 论坛上关于他的 项目/想法 的讨论。
我目前的总结如下(不确定是否准确):output-zero 的主要优势在于,它产生的证据的大小是 O(1) 级别(也即是恒定的)(得益于 Groth16),我记得大概是 260 字节。这显然比我的方法(证据体积在 3kB 左右)要好得多。但另一方面,从我自己测试它的结果(在此处)以及作者提供的概述来看,我并不相信它的证据生成时间是可以接受的。作者的论证是这样的:路由节点的设备通常配置很高,而且,更重要的是,证明并不是一个实时的操作,所以哪怕花上几分钟也无妨(似乎如果有 GPU 加速的话,那会快得多,但也许是我太老派了,我不觉得这种优势应该考虑在内(为什么呢?));至于验证,两种 ZKP 都要花上 50 到 200 毫秒。我怀疑在实践中,超过 10 秒的证据生成时间,就已经有点 “落伍” 了。也许我是错的。
但最后我要说,我认为这里最吸引人的地方在于,对于这些零知识证据应不应该跟具体的 通道 UTXO 相绑定,人们有不同的意见。如果你读了上面的 Delving Bitcoin 论坛上的讨论,你会发现我在这一点上也摇摆不定。我认为,不要尝试使用通道 UTXO,对隐私性会好得多;但是,从另一个角度看,为什么你想要使用并非通道的 UTXO 呢(你本来就已经给通道投入了流动性,为什么不使用它)?此外,如果你想在 ZKP 中使用通道 UTXO,那么你 应该/必须 支持这个证据要从 MuSig2 UTXO 中生成出来,这不仅要在 ZKP 的设计中考虑到(显然,如果 UTXO 不是只有一个主人的话,会更加棘手),还会引发一个问题:谁 可以/应该 使用这个 ZKP 作为一个资源凭证呢?关于这里的 ZKP 会如何受到影响,仅举一例,请看 output-zero 当前的设计,使用
hash(bitcoin-pubkey-1||bitcoin-pubkey-2)
作为它的 “密钥镜像”(用来防止你一遍又一遍重复使用同一个 UTXO 的东西,迥异于常见设计: “密钥镜像是私钥的不可反算的哈希值”)。我知道这对大多数读者来说过于苛求了,但只是为了演示其中的不确定性。
(完)