作者:Anony
BOLT12 是目前最新一个合并到 “BOLT(闪电网络基础协议)” 的规范。
人们常常会把 BOLT12 与 “LNURL” 对比。应该说,这种对比是合理的,而且抓住了 BOLT12 给闪电网络带来的最重要的新特性 —— 兼顾了隐私性的稳定身份标识。但 BOLT12 不止于此。
为了流畅地解释 BOLT12,我们先从 BOLT11 开始。
BOLT11 发票与标准的闪电支付
在常见的互联网支付中,往往要由收款方先出示一段信息(比如所谓的 “收款码” 和 “比特币地址”),然后支付方根据这段信息发起支付。闪电支付也不例外。
显然,这样的信息必须起到一个身份标识的作用。由 BOLT11 所定义的数据对象 “发票”,可以充当这个功能,但还不止于此。发票中包含了以下信息:
- 收款节点的公钥:即起到身份标识作用的信息,用于在闪电网络的图谱中寻找收款方的位置。
- 即使不直接包含收款节点的公钥,也会提供其它信息来帮助支付方定位。
- 支付哈希值:用于在闪电通道中建立承载多跳支付的哈希时间锁输出(HTLC)的哈希值。
- 支付秘密值:一个秘密值。
这些信息都是极为关键的:
- 支付哈希值用于建立免信任的接力支付,并且重要的是,当收款方为获得支付而释放出这个哈希值的原像之后,这个原像将沿着接力支付的网络路径反向传回给支付方,成为支付的证据;
- 支付的秘密值则用来分辨支付者的身份、防止接力支付的中间节点猜测路径的结尾(支付的收款方):由于收款者的发票只出示给了支付方,那么只有支付方知道这个秘密值,从而,可以要求抵达收款方节点的数据包裹包含这个秘密值,来拒绝非支付方的猜测和打探。
身份信息也许不需要用发票来传递,但上述两种信息与闪电支付密不可分。如果收款方没有向支付方传递发票,支付方就收不到支付证据,也就失去了使用闪电支付的一个关键好处。
这也是为什么发票必然是一次性的:支付哈希值和支付秘密值必须是一次性的,否则就无法建立安全的多跳支付,也无法获得上述好处。
剩下的问题仅仅是:给定发票是一次性的,无法成为收款方的稳定身份标识符,那么如何为收款方安排一个稳定标识符,使支付方总能按需请求发票?
LNURL 和互联网服务器
“LNURL” 以及衍生的 “Lightning Address” 协议,正是解决上述问题的一种方式。
这里的想法非常简单:假设收款方节点附带着一个总是可以访问到的网络端口,那么支付方就可以借助这个网络端口来向收款方节点请求 BOLT11 发票;一旦获得了发票,就可以开始正常的闪电网络支付流程。
这个网络端口的稳定可访问是重要的,但由谁来保证它可以访问则是相对次要的:收款方可以自设互联网服务器,也可以借助他人的服务器。LNURL 就是一套规定客户端如何与这样的服务端通信的标准。
使用 LNURL 之后,收款方就可以出示一个形如邮箱地址的 [email protected]
的 “闪电地址”,作为自己的稳定身份标识(收款码)。支付者只需 扫描/输入 这个地址并填入支付细节,请求发票和支付发票的流程都会在后台完成。
对于自己有能力或者使用 BTCPay Server 这样的服务的收款方来说,这是切实可行的解决办法。(更不用说使用托管型闪电钱包的用户了。)只是,使用了第三方的 LNURL 服务器,隐私性就会差一些。
那 BOLT12 做了什么呢?
BOLT12 的特性
BOLT12 的基本想法与 LNURL 没有什么不同,只是将它做进了闪电网络协议中,利用闪电网络自身的一系列基本特性来实现它。这种实现不仅减少了闪电网络用户对互联网服务器的依赖,还带来了一系列新功能:
- 在闪电网络中实现的对 “洋葱消息” —— 多层加密、逐层解密的网络转发消息 —— 的支持,让人们可以利用闪电网络本身来跟某一个节点通信;消息都是由闪电网络中的节点来转发的,中间节点并不知道消息的最终的目的地。
- “盲化路径” —— 由 消息/支付 的 收款方/接收方 自己设定,带有机密性的转发路径,则让接收方在提供定位信息的同时,不暴露自身的具体位置。盲化路径的阅读者只能知道这条路径的入口节点,而不知道其中包含的节点,因此也不知道接收方的具体位置,只知道依据这条路径,就能给接收方发送 支付/消息。
上述两者相结合,收款方就得到了一种兼顾隐私性的稳定身份标识,在 BOLT12 中称为 “offer(要约)”。Offer 中包含了盲化路径,这种信息是可以很稳定的,同时,又没有暴露收款方的具体位置。支付方只需要根据 Offer,使用洋葱消息向收款方请求发票(发送 BOLT12 所定义的 invoice_request
消息);收款方生成发票后,通过支付方在 invoice_request
中包含的 reply_path
发回给支付方;随后支付方便可依据发票发起支付。
基于这种稳定的身份标识,支付方可以多次向收款方请求发票并支付,从而订阅、捐赠、按量预付(随付随用)等支付场景也就成为了可能(原本需要依赖于网络服务端,如今不再需要)。
由于 Offer 在使用时要由支付方发起 invoice_request
,支付方可以在其中包含一个自己的公钥,从而在支付完成后得到一个支付者证明,这也是原来做不到的。
invoice_request
也可以反过来使用,从而使退款也变得便利:比如说,商家可以直接给出一个 invoice_request
,顾客依据其中的信息,向商家发送一张发票,从而让商家可以退款。
最后,还需要注意的是:通过 offer 来请求发票时,请求方获得的并不是 BOLT11 发票,而是由 BOLT12 所定义的发票。两者在功能上没有什么很大区别,都包含前述关键的支付哈希值和支付秘密值信息;一大关键区别是 BOLT11 发票使用 ECDSA 签名,而 BOLT12 发票使用 Schnorr 签名。
这是一个令人难以索解的事情:一方面,当前的 BOLT11 并没有给出使用盲化路径的方法,这是一种极为重要的隐私保护技术,如果 BOLT11 发票不支持,就将使 BOLT11 发票在功能上落后于 BOLT12 offer/发票,那么似乎用户没有理由再使用 BOLT11 发票,而应该完全依赖于 BOLT12 offer;然而,BOLT11 并没有从当前的 BOLT 中退出,意味着以后的客户端实现也必须 实现/维护 处理它的代码,这会影响协议的整洁。
就目前为止,还无法知道如何处理这种矛盾。唯一我们可以确定的事情是,BOLT12 确实能够改变闪电支付的体验,使闪电网络覆盖更多的支付场景。