作者:Jonas Nick
來源:https://github.com/BlockstreamResearch/scriptless-scripts/blob/master/md/multi-hop-locks.md
“多跳鎖” 指的是讓兩方可以交換資金和支付證據、無需手動為多簽名輸出注資的協議。也就是說,這兩方會通過兩兩具有共享的多簽名輸出的中間節點連接起來。當前,基於密碼學哈希函數的多跳鎖正在閃電網絡協議中用於轉發只是。
基於 “隱形腳本(scriptless script)” 的多跳鎖是在一篇 mimblewimble 郵件組的帖子中出現的,然後在論文《為區塊鏈可擴展性和互操作性而實現的保護隱私的多跳鎖》中得到了正式定義。通過使用隱形腳本,最終的交易體積更小、更接近於常規的交易,因此可以提高隱私性。更重要的是,它可以隱藏支付之間的關聯,意思是,參與一個多跳鎖的節點將無法確定自己是否在同一條路徑上,也即無法知曉他們是否在轉發同一筆交易(除非運行時序和資金數量分析)。支付關聯攻擊在整條轉發路徑的第一個和最後一箇中間節點由同一人控制時會變得格外危險,因為他們將知道一筆支付的來源和目的地。此外,隱形腳本多跳鎖還支持優化的支付證據以及 “原子化的多路徑支付”(詳見下文)。
記號
Pij
是用戶i
和j
的 MuSig2 聚合公鑰。MuSig2 論文提供了更多細節。T := t*G
,其中t
是一個隨機選出的數值,稱作 “適配器秘密值”,而T
稱作 “適配器點”。psig(i, m, T)
表示來自簽名人i
對消息m
的、使用適配器點T
的碎片簽名,該簽名可以用來聚合成為一個 2-of-2 的 MuSig2 簽名。出於簡潔,另一個簽名人沒有表示在記號中;通常來說,另一個簽名人是i
與之有通道的節點,會隨語境確定。之所以說這是一個 “碎片”,是因為它需要跟另一方的碎片簽名加總,然後才能成為一個有效的 Schnorr 簽名。此外,也有人會說它是 “預備” 的碎片簽名,因為還需要加上適配器秘密值t
,才能成為一個常規的碎片簽名。sig(m, T) := psig(i, m, T) + psig(j, m, T) + t
,是最終來自用戶i
和j
的完整 Schnorr 簽名。
協議
在初始化階段,支付的接收者先隨機選出一個 z
,並將 z*G
發送給支付的發送者。發送者將建立一套多跳鎖,確保成功的支付會向她揭曉 z
,並且僅向她揭曉。對 z
的知識可以成為一項支付證據,就像當前閃電網絡中的 “支付原像” 類似(細節見下文)。
我們將支付流程描繪為從左邊的發送者開始、經過中間節點、到達右邊的接收者。
然後,發送者要按下述方式,為每一個節點 i
建立一個元組 (Li, yi, Ri)
,該元組包括了 左向鎖 Li
和 右向鎖 Ri
:
- 每一個
yi
都是一個均勻隨機選出的標量(scalar) - 發送者自己的左向鎖
L0
被設置成了z*G
,是之前從接收者處收到的。 - 對於節點
0 <= i < n
的右向鎖、以及節點j = i + 1
的左向鎖Lj
,發送者設為Ri <- Li + yi*G
以及Lj <- Ri
(見上圖)(譯者注:意思是,上一個節點的右向鎖即是下一個節點的左向鎖)
注意,在閃電網絡中,發送者不會直接把 (Li,yi,Ri)
發給中間節點:TA 會使用洋蔥數據包,以攜帶這些數值,同時不讓中間節點知道自己的身份。
在更新階段,相鄰的節點會在他們的鏈下交易中加入一個多簽名輸出,就像當今的閃電網絡中在交易中添加一個 HTLC 輸出一樣。我們把這種新型的隱形腳本輸出叫做 “點時間鎖合約(PTLC)”。跟 HTLC 一樣,PTLC 也有一個超時條件,讓左邊的節點可以在支付失敗時回收自己的資金。但不同的是,PTLC 只是普通的 2-of-2 MuSig2 輸出,而哈希鎖是僅在收到一個碎片簽名時隱式地加入輸出中的(詳見下文)。出於演示的目的,我們假設使用 eltoo 形式的通道,意味著雙方有對稱的狀態,而且無需撤銷。
如果支付沒有超時,那麼由相鄰兩個節點分享的隱形腳本 PTLC 輸出中的資金會被右邊的節點取走。因此,左邊的節點 i
要創建一筆交易 txj
,花費該 PTLC 並將資金髮送到由右邊的節點 j
控制的一個輸出中。假設 MuSig2 簽名協議所需的 nonce 值交換輪已在雙方都更加方便的早些時候發生(例如,在建立一個連接的時候),從而這一輪通信不會發生再支付的關鍵過程中。
收到新 PTLC 的通知之後,右邊的節點 j
會創建交易 txj
以及對 txj
的碎片簽名 psig(j,txj,Lj)
。左邊的節點要驗證這個碎片簽名,然後給右邊的節點發送自己對 txj
的碎片簽名,在以下兩種情形中:
- 左邊的節點是發送者
- 左邊的節點
i
收到了來自前序節點i-1
對txi
的簽名psig(i-1,txi,T-yi*G)
。結合剛剛收到的來自右邊節點的碎片簽名,就可以保管,只要右邊的節點花費了資金,左邊的節點可以開啟左向鎖、用txi
取走資金,如上圖所示。
因此,更新階段從最左邊的一對節點開始,一直持續到最右邊的一堆節點。在收到來自左邊的節點的碎片簽名後,右邊的節點可以在知曉其左向鎖秘密值之後儘快補完那個簽名。為了減少整體的通信輪次,啟動節點和更新階段可以合在一起(例如,使用閃電網絡中的洋蔥數據包)。
結算階段則從接收者收到來自其左邊的節點的碎片簽名後開始。多跳鎖是由發送者建立的,接收者可以將自己的秘密值 z
加到左邊節點的碎片簽名中,然後用自己的碎片簽名再加總上面的結果。最終,TA 可以得到一個對右邊節點(接收者)交易有效的簽名。這時候,右邊的節點可以可以廣播交易、到鏈上結算了(如果左邊的節點消失或嘗試欺詐的話)。
在左邊的節點知曉交易的簽名之後,就可以通過減去之前從右邊的節點收到的碎片簽名以及自己的碎片簽名、從而知曉右向鎖秘密值:
sig(tx,T) - psig(i,tx,Ri) - psig(j,tx,Lj) = yj
或者,右邊的節點可以直接將秘密值 yj
發送給左邊的節點,然後請求更新承諾交易(基於 LN-penalty)或結算交易(基於 eltoo),從而移除 PTLC,然後左邊的節點的輸出就會減去支付數額,而右邊節點的輸出就會加上支付數額。如果左邊的節點不跟著更新,右邊的節點依然可以在 PTLC 超時之前廣播自己的交易。
不論如何,只要接收者領取了支付,左邊的節點就能知道右向鎖秘密值,然後可通過減去 yi
計算出其左向鎖秘密值、然後創建出對她自己的交易的最終 Schnorr 簽名。每一個節點上都會發生這個過程,直至發送者,TA 將知曉用來完成支付的支付證據 z
。
支付的證據(PoP)
基於 PTLC 的多跳鎖與基於 HTLC 的多跳鎖的區別在於,支付證據(z
)只有發送者能夠知道,而不是沿路每一個節點都能知道。因此,支付證據可以用來向接收者鑑別支付者的身份。不需要揭曉 PoP 本身,可以提供 z*G
的簽名。因為支付間的關聯被取消,中間節點無法將 PoP 與一筆關聯起來。
顯然,不止發送者能知道 z
。接收者和發送者願意與之分享 z
的任何人都可以知道,因此還是不清楚誰是真正的支付者。因此,來自接收者、發給發送者的一個簽名陳述(閃電發票)應該包含 z*G
和發送者的公鑰。然後,PoP 就既包括 z
的一個簽名,也包括髮送者私鑰的簽名,這是隻能由發送者(或發送者選擇合作的人)提供的。
理想情況下,如果一個靜態的發票可以被多方支付,那就允許互助式支付,並且不需要跟接收者額外通信。但這跟支付證據是不相容的,因為 PoP 必須在每一筆支付發生時從即時的隨機性中創建出來。不過,同一發送者的反覆支付可以使用哈希鏈條來實現。
原子化的多路徑支付(AMP)
使用隱形腳本多跳鎖,就有可能實現類似於 “base MPP” 的多路徑支付,同時,允許隱匿路徑間的支付關聯。發送者使用互無關聯的鎖來創建通向接收者的多條路徑、使得接收者領取任何一部分支付都會向發送者揭曉支付證據(z
)。因為接收者並不希望只領取一部分支付時就給出 PoP,她會等待所有路徑都完全建立、然後一次性拿走所有的部分付款。
在最初的 “base AMP 提議” 中,“原子性” 不是僅僅靠激勵來實現的,還依靠於有意的路徑規劃、使得接收者的秘密值(z
)僅會在所有路徑都建立時才一次性揭曉。不過,在這一提議中,支付方無法獲得支付證據。使用隱私腳本多跳鎖,我們就技能獲得原本的 base AMP 提議的原子性,又能獲得支付證據。這被稱作 “high AMP”。
在 high AMP 中,發送者首先選出一個隨機數 q
,然後根據路徑的數量 n
選出一些隨機數 q1,...,qn
、使得 q = q1 + ... + qn
。發送者在每一條路徑的接收者的支付點中都加入 q*G
。這樣依賴,接收者就無法領取任一部分支付,因為 TA 根本不知道 q
。但是,在發送者規劃的每一條路徑 i
中,都向接收者發送了一個 qi
。從而,當且僅當所有路徑都成功建立,接收者可以計算出 q
並領取支付。
可取消的支付
在當前的閃電網絡中,支付可能會被卡住很長一段時間,如果中間節點在轉發支付時下線的話。支付者無法安全地重試(其它路徑),因為(原路徑的)中間節點可能又會在 PTLC 超時之前回到線上、讓支付者重複支付。
案例場景:
- Alice 給 Bob 發送一筆價值 10mBTC 的 PTLC,希望 Bob 轉發給 Dave(Alice -> Bob -> Dave)。
- Bob 收到這個 PTLC 之後並不轉發任何東西給 Dave。
- 等待少數幾個區塊之後,Alice 失去了耐心,嘗試通過 Carol 來轉發支付(Alice -> Carol -> Dave)。
- 這一次支付成功了,Alice 正確地支付了 10mBTC 給 Dave,並且收到了支付證據。
- 但是,Bob 在他的 PTLC 超時之前突然上線了,又轉發了 10mBTC 給 Dave。
- 對 Dave 來說,這是天上掉餡餅,所以 Dave 接受了,也回傳了支付證據。
- 最後,Alice 又收到了一次支付證據,但她已經支付了 20mBTC,而不是 10mBTC。
這是可以避免的,如果支付需要來自發送者的一個秘密值才能完成的話。這個解決方案最初用名 “無滯支付”。
發送者的秘密值是 y0 + y1 + y2
。在初始化階段,Alice 不能發給 Dave。Alice 把 (z + y0 + y1 + y2) * G
作為 Dave 的左向鎖,也就是讓 Dave 揭曉 (y0 + y1 + y2) * G
。在更新階段的末期,Dave 無法創建簽名,因為他根本不知道 y0 + y1 + y2
。Dave 可以向 Alice 請求 y0 + y1 + y2
(並出示 (y0 + y1 + y2) * G
以證明自己已經收到了 PTLC)。當 Alice 收到這個請求時,她就知道,這個 PTLC 已經正確地傳遞給了 Dave。她可以安全地發送 y0 + y1 + y2
給 Dave,讓 Dave 可以開啟結算階段。
注意,這不能防止支付在結算階段空竹(如果有節點掉線的話)。但是,中間節點有大得多的激勵在結算階段保持在線:
- 在更新階段,他們會收到來自左邊的對等節點的比特幣:他們還沒有發送任何東西,所以唯一的激勵是他們將收到的轉發手續費
- 在結算階段,他們已經發送了比特幣給自己右邊的對等節點:現在,他們有了激勵回傳支付證據,以收取入賬支付