在链上向 Phoenix 钱包存入资金现在变得更便宜(*),也更隐私,这都得益于过去几年添加到比特币和闪电网络上的强大新功能的组合。
作者:ACINQ
摘要:在链上向 Phoenix 钱包存入资金现在变得更便宜(*),也更隐私,这都得益于过去几年添加到比特币和闪电网络上的强大新功能的组合。
(*)在 swap 交易只有一个输入时便宜了 16%,有两个输入时便宜了 23%,而在三个输入时便宜了 27%。
去年,我们为 Phoenix 钱包软件发布了一个重大升级(中文译本):用户可以只使用一条通道,通道的容量可以按需扩大和缩小。
在那次升级中,一项关键的特性就是免信任的、即时的 “swap-in”:当资金被发送到你的钱包的链上地址(swap-in 地址)时,这些资金会通过 swap-in 交易 “拼接” 进入你已有的闪电通道。
但那一套 swap-in 协议还不能尽如人意:
使用 Taproot、MuSig2 以及描述符,我们设计并实现了一种新的 swap-in 协议:swap-in 交易现在变得更加便宜,也更难跟踪,而且 Phoenix 钱包会在每次你想要链上收款时为你生成一个新的 swap-in 地址。
一笔 swap-in
交易就是一笔链上交易,可以用来为一条闪电通道增加资金。Phoenix 使用了一套基于 “swap-in potentiam”(中文译本)的免信任的、即时的 swap-in 协议。
这套协议跟 “零确认”的理念是兼容的,而 “零确认” 是 Phoenix 钱包使用体验的一个关键:在 swap-in 交易还在等待链上确认时,通道依然是可用的;一旦交易获得确认, Phoenix 钱包就会触发零确认的通道拼接(默认拼入通道的资金已经可用)。
之前,我们使用的是一种 pay-to-script 构造,脚本是 用户公钥 + 服务商公钥 OR 用户公钥 + 时延
。这里,“用户” 指的是 Phoenix 钱包的一个用户,而 “服务商” 指的是 ACINQ 闪电节点。
有两种办法可以花费这个脚本:
但这种设计有一些缺点:
“Taproot”(详见 BIP 340 和 BIP 341)是比特币的一个重大升级,为比特币协议带来了许多提升,包括:
最后一项对我们的新的 swap-in 协议非常关键。Taproot 引入了 key-path spending
(使用公钥来花费)和 script-path spending
(使用脚本来花费)的概念。
在以往的比特币交易中,你只能在 pay-to-script 和 pay-to-public-key 之间选择一种,但有了 Taproot,你可以两者都要。你可以实现 pay-to-public-key OR pay-to-script
这样的协议,这样,当你在使用 pay-to-public-key 条件时,你的花费交易将跟其它 pay-to-public-key 构造的花费交易没有区别。
所以,回到我们的 swap-in 脚本:用户公钥 + 服务商公钥 OR 用户公钥 + 时延
。为了在合作情形中使用 key-path spending
,我们需要把 用户公钥 + 服务商公钥
换成一把公钥。这是怎么做到的呢?
有了 Schnorr 签名,加总公钥和签名就变得非常简单。事实上,如果你用 N 个私钥对同一条消息生成了 N 条签名,你可以把这 N 条签名全部加起来(成为 “聚合签名”),然后把对应的 N 个公钥全部加起来(成为 “聚合公钥”),这个聚合签名就是这个聚合公钥的有效签名。
非常非常简单 …… 而且根本不安全!
事实证明,因为加总非常简单,所以在你使用公钥 P
的时候,攻击者可以使用 -P
,把你的公钥 “取消掉”。
因此,我们需要 “MuSig2”,这是一种用来聚合签名和公钥的算法,可以证明是安全的,而且已经在生产环境中就绪了。
所以,有了 MuSig2,我们可以真的把用户公钥和服务商公钥聚合成一个公钥,然后用在 key-path
花费中,然后我们的脚本就变成了:用户-服务商 聚合公钥 OR 用户公钥 + 时延
:
在合作情形中,使用 swap-in 资金的通道拼入交易会变得更加便宜,而且跟其它的 pay-to-taproot-address 交易没什么区别。很棒!
但 swap-in 地址能不能换呢?如何既能轮换地址,又能提供一种通用的资金复原流程、保证可以扫描所有可能的 swap-in 地址?
“描述符” 是一种简单的语言,可以用来描述标准钱包的范式,包括 BIP32 密钥生成的模式。
描述符可以使用 “miniscript” 来描述大部分标准的脚本范式。Miniscript 支持 Taproot,但(还)不支持 MuSig2:它可以显式地说明 key-spend 公钥以及 script-path 脚本(包括地址的生成)。
为了让我们的 swap-in 协议与 miniscript 描述符兼容,我们只需要为合作情形使用一个固定的用户公钥(*),而在退款分支中可以使用不同的退款公钥(可以使用 BIP32 方案),从而:
这就是 swap-in 复原描述符的样子:
tr(
// 使用固定的 key-path 花费密钥
1fc559d9c96c5953895d3150e64ebf3dd696a0b0...48ff6251d7e60d1,
// 下面则是 secipt-path 花费脚本
and_v(
// the xprv with the derivation path
v:pk(xprvA1EfxcCy5HJnYBfPmwi9iXAyCktUSN...tvYsWqFTu29/...),
// CLTC timeout
older(2590)
)
// checksum
)#sv8ug44m
(*)每一个 Phoenix 钱包都有一个唯一的用户公钥以及一个唯一的服务商公钥(两个都是从你的 12 词种子词中推导出来的)
我们的 swap-in 协议站在了巨人的肩膀上:
所有这些特性和协议乍看起来都暗淡无光,可能也很难看出它们对终端用户有什么好处。但现在,清楚起来了:它们是开发更好、更便宜、更隐私也更易用的协议的工具。这正是 Phoenix 的使命!
(完)
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!