多方的潜水艇互换

  • BTCStudy
  • 发布于 18小时前
  • 阅读 53

本文介绍了多方参与的潜水艇互换(Submarine Swaps)方案,旨在提高闪电网络中链上和链下资产互换的效率。通过将传统的两方互换扩展到多方,可以减少链上交易的足迹,提高吞吐量。文章详细讨论了链上到链下以及链下到链上两种互换场景,并提出了减少恶意行为的措施,如手续费、预存系统和忠诚债券。

作者:conduition

来源: https://conduition.io/scriptless/multi-party-submarine-swaps/

潜水艇互换” 允许闪电网络上的用户免信任地将链内的 UTXO 置换成闪电通道中的余额。它基本上就是用于闪电网络的原子化互换,并且对闪电节点运营者极其有用(可用来重新平衡他们的通道,以及其他事项)。

随着潜水艇互换变得日益重要和常见,也许是时候该看看如何更好地扩大潜水艇互换的吞吐量了 —— 如今,更多的对等节点和流动性提供者可以参与互换。

回顾

传统的潜水艇互换是一种两方的原子化互换,使用两个哈希时间锁合约(HTLC):一个部署在比特币链内;另一个部署在闪电网络中。

假设 Alice 想要卖出链内的比特币,换成一笔闪电支付;而 Bob 想要使用他的闪电通道余额来购买 Alice 的链内资金。

首先,Alice 要生成一个只有她自己知道的随机秘密值 $s$ 。

Alice 和 Bob 构造一个 2-of-2 的托管地址:如果 Bob 知晓了 $s$ ,将拥有这个地址的完全花费权限,这是用一个哈希锁条件来表达的;此外,在网络达到特定的区块高度 $B$ 之后,Alice 将获得这个地址的完全花费权限。

这是一个用描述符来表达的案例:

tr(
  musig(<alice_pubkey>, <bob_pubkey>),
  {
    and(sha256(<hash>), pk(<bob_pubkey>)),
    and(after(<B>), pk(<alice_pubkey>))
  }
)

Alice 把自己的钱币存入这个 2-of-2 托管合约,确信自己可以在区块高度 $B$ 之后重新拿回资金,以及,Bob 当前是无法取走其中的钱的,因为只有她自己知道 $s$ 。

然后,Alice 给 Bob 一个闪电发票,其要求支付的数额与钱币的面额一样,并使用 $SHA256(s)$ 作为支付哈希值。Bob 可以支付这个发票,同时(通过 HTLC 的时间锁)要求 Alice 最晚在区块高度 $B - \Delta$ 就要释放原像(领取支付),这里的 $\Delta$ 是合理的时间延迟。如果 Alice 领取了 Bob 的闪电支付 HTLC(不论是与自己的通道对手完成协商,在链外释放原像、领取资金;还是强制关闭通道,Alice 在链内曝光原像来领取),Bob 就会知道 Alice 的秘密值原像 $s$ ,然后他就可以转走 上述托管合约中的资金。如果 Alice 很狡猾,到最后一刻,也就是区块高度 $B - \Delta$ 才领取支付,Bob 也拥有 $\Delta$ 个区块来知晓 $s$ 并使用它来领取 Alice 在链内的 HTLC(即上述合约)。

就是这样!Bob 和 Alice 可以彼此置换链内和链外的钱币,双方都没有机会欺诈对方。为了提升隐私性和效率性,Alice 和 Bob 可以合作:一旦 Bob 支付了闪电发票,双方就使用 MuSig 来联合签名花费上述合约的交易、将资金转移给 Bob(从而外人无法看出这是一笔 HTLC/潜水艇互换 交易)。

效率

一些潜水艇互换供应商,比如 Lightning Labs 的 Loop 服务,会批量处理他们的链内交易。在清扫他们收到的链内钱币之时,一次清扫多个合约可以更好地将大量资金归集到少量的 UTXO 中。在给潜水艇互换的托管合约地址注资时,也可以这样做,每个输出都给一个独立的潜水艇互换合约注资。

但是,这里依然有一个效率瓶颈,来自潜水艇互换协议自身的拓扑。我们有许多小节点(用户),全部都跟一个潜水艇互换服务商(比如 Loop 或 Boltz)交互。用户们完全不知道其他人的交易,所以每一笔潜水艇互换都是一个完全独立的合约,发生在一个用户和一个互换服务商之间。这就产生了浪费。

而每一个从链内钱币到链外支付的潜水艇互换,都要求用户发起一笔单独的注资交易,因为用户们不知道彼此,所以无法一起批量处理他们的主子交易。此外,每一个潜水艇互换都会创建一个独立的注资交易输出,所以,即使注资交易 得到了 批处理(就像 Loop 的链外到链内协议一样),我们依然有 $n$ 个单独的注入了资金的 HTLC 地址,可能要用 $n$ 笔额外的交易来解决。

扩容

我们可以通过将潜水艇互换从单一接单者协议转变成 $n$-吃单者协议,来提高效率。 我们不再假设在每次互换中都是一个挂单人(maker)和一个吃单人(taker),而是假设有一个挂单人 以及 $n$ 个吃单人,他们有能力进行带有身份认证的通信,不论是通过 P2P 还是一个代理(比如挂单人)。这些参与者将通过将他们的 $n$ 个潜水艇互换合约聚合成一个注资 UTXO,一起执行一次免信任的原子化互换。

这会增加协议的复杂性和碎片化,但也能极大地提高链内效率。我们来看看这是怎么做到的。

链内 -> 链外 互换的吃单人

我们先来看看 $n$ 个吃单人参与从链内到链外资金置换的情形。在这种情形下,交易的两边是:

  • 吃单人:一组 $n$ 个吃单人,希望将小额的链内 UTXO 换成链外的闪电通道余额。
  • 挂单人:单个个人或企业,希望将闪电余额换成链内资金。

不像传统的潜水艇互换中那样,吃单人们注资 $n$ 个链内单独的链内托管地址 —— 而是一起注资到单个托管合约中,并且资金是在单笔交易中转入的 —— 这个托管合约,要么被挂单人花掉(如果合约执行顺利的话),要么退回给各位吃单人(如果合约执行不顺利的话)。

  1. 挂单人生成 $n$ 个随机秘密值 ${s_1, s_2, …, s_n}$(为每个吃单人安排一个)。
  2. 吃单人和挂单人一起创建一个 n-of-n 的 taproot 哈希锁地址,如果挂单人可以揭晓 ${s_1, s_2, …, s_n }$,就能从这个地址中转走资金。

以下是一个用描述符来表示的三重哈希锁案例:

tr(
  musig(
    <taker1_pubkey>,
    <taker2_pubkey>,
    <taker3_pubkey>,
    <maker_pubkey>
  ),
  and(
    hash160(<hash1>),
    hash160(<hash2>),
    hash160(<hash3>),
    pk(<maker_pubkey>)
  )
)

使用 taproot 脚本,我们可以(通过聚合公钥协议)使用 4-of-4 的内部公钥,从而,在各方都配合的情况下,将体积很大的哈希锁完全隐藏起来。我们使用 hash160 而费 SHA256 是为了节约区块空间,同时保留在闪电网络中以相同的秘密值(原像)使用 HTLC 的选择。

  1. 吃单人们构造一笔 注资交易,将众人的 UTXO 支付给上述多签名地址(可能会有找零输出)。吃单人们 暂不 签名注资交易。
  2. 吃单人们构造一笔 超时交易,也即退还款项的交易。这笔超时交易将 注资交易 输出中的资金返还给各吃单人。 超时交易 必须带有一个解锁时间点为区块高度 $B$ 的绝对时间锁。
  3. 吃单人和挂单人一起签名 超时交易。挂单人当然没有意见,因为它带有绝对时间锁。
  4. 挂单人建立 $n$ 个闪电网络 HTLC,每个 HTLC 为其中一个吃单人支付对应的互换金额。给吃单人 $i$ 的 HTLC 使用 $SHA256(s_i)$ 作为支付哈希值。各吃单人的互换金额可能不一样。吃单人们还无法 领取 这些 HTLC ,因为只有挂单人知道每一个 HTLC 的原像 ${s_1, s_2, …, s_n }$ 。这些 HTLC 的绝对时间锁必须至少是 $B + \Delta$ ,其中的 $\Delta$ 就是一个合理的时延(以区块为单位)。
  5. 在所有的吃单人都在自己的通道中收到了 HTLC 之后,吃单人们一起签名并发布 注资交易
  6. 所有人等待注资交易得到区块确认。

挂单人有三种选择。

1. (链内)强制执行

挂单人可以使用原像 ${s_1, s_2, …, s_n }$ 在哈希锁花费路径中领取注资交易输出。这样的 申领交易 会在网络中揭晓所有原像,从而吃单人们可以用这些原像来领取各自收到的 HTLC 中的资金。

即使挂单人拖到最后一刻才发布 领取交易,吃单人们依然有 $\Delta$ 个区块的时间窗口来领取各自通道中的 HTLC 中的资金。

2. (链外)合作

挂单人可以将 ${s_1, s_2, …, s_n }$ 中的每一个分别交给对应的吃单人。吃单人可以使用这些原像来领取自己通道中的 HTLC 。作为交换,吃单人们应该跟挂单人配合签名一笔交易,从而将注资交易输出中的资金释放给挂单人。

即使有人拿原像兑换 HTLC 之后拒不交出签名,挂单人依然可以在链内强制执行、取走注资交易输出中的资金。

请注意,挂单人只交出 一部分 原像(而不是全部交付)是不理性的,因为实质上,每一个原像都是从挂单人处领取一些资金的权利。只要挂单人想在链上取走资金,就必然要揭晓所有的原像,而不是一部分。

3. 超时

挂单人可以选择不揭晓任何原像。因此,吃单人将无法领取各自通道中的 HTLC 。当网络达到区块高度 $B$ 的时候,任何一个吃单人都可以发布 超时交易,从而让资金返还给各吃单人。再过 $\Delta$ 个区块,他们各自通道中的 HTLC 也将过时。

性能

如果使用 $n$ 次传统的潜水艇互换,链内的足迹最少也将是:

  • $n$ 个不同的注资交易,每笔交易至少包含 1 个输入和 1 个输出
  • $n$ 个不同的输入,领走各托管地址中的资金(也许可以批处理成单笔交易)

在理想情况下,我们这里的多方互换方法可以将($n$ 次互换)链内足迹减少到:

  • 注资交易将至少有 $n$ 个输入,至少 1 个输出(可能会更多,因为有找零输出)
  • 1 个输入,领取注资交易输出(也许可以跟其它领取交易批量处理)

值得指出的是,如果 $n$ 较大,一些吃单人不配合,为了在链内领取注资交易输出,挂单人可能需要在交易的见证输出中发布大量的 RMD160 哈希值和一个体积巨大的脚本。这可能会影响性能分析和 $n$ 的选择。

链外 -> 链内 互换的吃单人

现在,来看看我们的方法在相反的情形中是如何工作的。

这时候,参与交易的两种角色是:

  • 吃单人:多个小体量的参与者,希望将闪电通道中的余额换成小额的链内 UTXO 。
  • 挂单人:单个个人或企业,希望将大额的链内 UTXO 换成闪电通道内的余额。

这时候,挂单人不再像传统的潜水艇互换那样生成 $n$ 个单独的链内托管地址,而是为一个托管地址注入资金,预期这个地址会在单个交易中花费 —— 要么是发送资金给各吃单人(如果互换顺利)、要么是返回给挂单人(如果互换不顺利)。

  1. 挂单人生成 $n$ 个随机秘密值 ${s_1, s_2, …, s_n }$(为每个吃单人安排一个)。
  2. 吃单人和挂单人一起创建一个 1-of-n 的 taproot 哈希锁地址

以下是一个用描述符来表示的吃单人数量为 3 的案例:

taker_joint_pubkey = musig(
  <taker1_pubkey>,
  <taker2_pubkey>,
  <taker3_pubkey>
);

tr(
  musig(
    <taker1_pubkey>,
    <taker2_pubkey>,
    <taker3_pubkey>,
    <maker_pubkey>
  ),
  {
    {
      and(
        hash160(<hash1>),
        pk(taker_joint_pubkey)
      ),
      and(
        hash160(<hash2>),
        pk(taker_joint_pubkey)
      )
    },
    and(
      hash160(<hash3>),
      pk(taker_joint_pubkey)
    )
  }
)

注意,在这个脚本中,吃单人是 3 个不同的哈希锁花费条件的联合收款方,也就是说,<hash1><hash2><hash3> 三个原像中的任何一个,都可以被吃单人用来领取其中的资金。

  1. 挂单人构造一笔 注资交易,它花费挂单人的 UTXO ,支付到上述 taproot 地址中(交易可能带有诏令输出)。挂单人 暂不 签名这笔注资交易。
  2. 挂单人构造一笔 超时交易,它花费 注资交易 的输出,将资金返回给挂单人。带有解锁时间点为区块高度 $B$ 的绝对时间锁。
  3. 吃单人和挂单人一起签名 超时交易。吃单人愿意接受,因为超时交易有绝对时间锁。
  4. 吃单人们合作构造 $n$ 笔 领取交易,每一笔领取交易都使用注资交易输出的不同哈希锁花费分支来花费它、在吃单人们之间分割资金。吃单人们合作签名所有 $n$ 笔 领取交易,没有任何一笔会被公开,直到 ${s_1, s_2, …, s_n}$ 中的一个被揭晓。吃单人们都愿意签名这些交易,因为这些交易不会侵吞属于他们自己的资金。每一个吃单人 $i$ 都必须获得对应于自己的哈希值 $RMD160(SHA256(s_i))$一笔完全签名的领取交易,从而,只要吃单人 $i$ 知晓了 $s_i$,就能够发布领取交易。
  5. 挂单人签名并广播 注资交易
  6. 每个人都等待注资交易得到区块确认。
  7. 吃单人们建立 $n$ 个 HTLC 并通过闪电网络支付给挂单人,支付参与互换的金额,使用对应于自己的 $SHA256(s_i)$ 作为支付哈希值。吃单人们可能会使用不同的数额。每个 HTLC 的超时时间最晚也只能是 $B - \Delta$ ,这里的 $\Delta$ 是合理的时间延迟(以区块数量为单位)。 挂单人必须等到所有的 HTLC 都送达之后,才能结算其中任何一个。
  8. 挂单人可以使用原像 ${s_1, s_2, …, s_n }$ 来结算任何一个 HTLC (也可以全部结算)。也就是任何一个吃单人都会获得至少一个原像 $s_i$ 。请注意,理性的挂单人要么会领取 所有的 HTLC,要么 一个都不领。因为哪怕揭晓一个 $s_i$ ,都会让吃单者们取走注资交易的输出中的资金。

1. (链内)强制执行

任何一个吃单人 $i$,在知道原像 $s_i$ 之后,都可以发布一笔 领取交易(是早前由所有吃单人签名过的)。这笔原子化的交易会将挂单人的资金在吃单人之间公平分配。

即使挂单人希望等到其闪电通道内的 HTLC(根本上来自各位吃单人)超时之前的最后一刻才揭晓所有原像 ${s_1, s_2, …, s_n}$ ,也即最坏情况下,吃单人们也将拥有 $\Delta$ 个区块的时间窗口来发布和确认一笔 领取交易

2. (链外)合作

一旦挂单人领取了其闪电通道内所有的 HTLC,也即所有的原像 ${s_1, s_2, …, s_n}$ 都曝光了,挂单人可以跟吃单人们配合签名一笔新版本的领取交易,使用那个 4-of-4 的内部公钥。这让他们可以藏起合约中的哈希锁花费分支,提高隐私性和链内效率。

如果有人不签名这个新版本的领取交易,某一个吃单人可以退回到发布自己的 领取交易,只需在区块高度 $B$ 之前(在 超时交易 变成有效交易之前)。

超时

如果挂单人什么也没做(不释放原像),那么来自吃单人的 HTLC 会在区块高度 $B - \Delta$ 过期,从而给吃单人返回闪电通道余额。然后,等到区块高度 $B$ ,挂单人就可以用超时交易来清扫注资交易输出。

如果吃单人在挂单人发布 注资交易 之后不再响应,挂单人什么都不需要做,只需等待区块高度 $B$ ,然后发布超时交易。

性能

如果使用 $n$ 次传统的潜水艇互换,链内的足迹最少也将是:

  • $n$ 个不同的托管输出(也许可以批量处理为用一笔注资交易生成)
  • $n$ 笔不同的交易来领取上述托管输出,每笔交易都至少包含 1 个输入和 1 个输出(无法批量处理)

在理想情况下,我们这里的多方互换方法可以将($n$ 次互换)链内足迹减少到:

  • 1 个托管输出(也许可以批量处理为一个较大体积的注资交易)
  • 1 笔领取交易,带有 1 个输入和 $n$ 个输出(在吃单人之间分配资金)

在部分吃单人或挂单人不合作的情形中,吃单人需要使用其中一个哈希锁分支来领取链内资金。

减少骚扰

尽管将潜水艇互换拓展为多方协议是显然有可能的,但这样做可以获得具体多少效率提升,是可以争议的,因为这很大程度上取决于过程中的各方是否配合。从链内到链外的互换尤其如此,只要一个吃单人不合作,就可以迫使挂单人支付额外的手续费来(发布一连串似乎毫无必要的哈希值和原像)领取资金。

同样的骚扰攻击在传统的潜水艇互换协议中也存在,但在多方参与的环境中影响更大,因为一颗老鼠屎就能弄坏一锅汤(让互换对每个人都变得更贵)。

为了遏制来自吃单人的骚人,挂单人可以实现以下技术:

  • 手续费。挂单人可以在闪电发票金额中加入手续费,要求吃单人支付(在从链外到链内的互换中);或者,可以减少在 HTLC 中支付给吃单人的数额(在从链内到链外的互换中)。这将激励挂单人提供互换服务,并让骚扰攻击变得更加昂贵。
  • 预存系统。挂单人可以强迫吃单人预先提供一个数额为互换金额的小比例的 HTLC 作为存款(使用 “HODL 发票”)。如果吃单人在互换过程中批核,则挂单人可以取消发票、退回存款。如果吃单人不配合,挂单人可以结算发票、取走存款,作为惩罚。这种存款不是免信任的 —— 挂单人可以无条件取走它;所以,需要一定程度的信任、责任感和声誉。
  • 匿名使用的 token 。吃单人可以从挂单人处购买一些 ecash token ,日后,将它兑换为与挂单人参与一次多方潜水艇互换的资格。
  • 忠诚债券。这将允许匿名的挂单人或吃单人通过牺牲一些比特币来换取一个永久的 挂单人/吃单人 身份,证明自己会诚实参与交易。

为了的工作

  • 闪电网络上的 “点时间锁合约(PTLC)” 将允许显著提高两个方向上的多方潜水艇互换的链内隐私性和效率。那么,基于 PTLC 的多方潜水艇互换会是什么样的?到底能获得多少效率提升?
  • 是否有可能执行 n-to-m 潜水艇互换,即 $n$ 个链内 UTXO 的卖方与 $m$ 个通过闪电支付来购买的买方达成交易?

(完)

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
BTCStudy
BTCStudy
https://www.btcstudy.org/