Develop with pleasure!

福岡でCloudとかBlockchainとか。

秘密鍵をオフラインにしたままLN支払いを受け入れ可能にするFast Forwardプロトコル

Lightning Networkでオフチェーン支払いをする場合、(オンチェーンの支払いと違って)チャネル参加者は常にオンラインである必要がある。その際、支払いによる状態の更新で新しいコミットメントトランザクションに署名するため、秘密鍵も同様にオンラインである必要がある。

そんなオンライン要件を緩和する方法が提案された↓

https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-June/003045.html

ベースになってるプロトコルは2019年にZmnSCPxjが提案したネットワーク帯域幅レイテンシーを削減するFast Forwardという仕組み↓

https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-April/001986.html

提案では、チャネル参加者の内、受信者の秘密鍵をオフラインにできる。ただし、

  • 支払いの送信者の秘密鍵はオンラインのまま。これには自分→相手へのルーティングも含まれるので、オフラインにできるのは自分が最終の受信者である場合のみ。
  • 秘密鍵はオフラインにできるが受信者自体はオンラインである必要がある。
  • チャネルを一方的に閉じられた場合は、秘密鍵をオンラインにして署名する必要がある。

Poon-Dryjaスタイルのペイメントチャネル

現在のLightning Networkは、Poon-Dryjaスタイルのペイメントチャネルを採用している。この場合、アリスとボブの二者間でチャネルを開いていると仮定し、両者はそれぞれコミットメントトランザクションを保持している。コミットメントトランザクションは、両者の残高を表す2つのアウトプットを持つ。

1つは自分宛(to_local)、もう1つは相手宛(to_remote)。この2つのアウトプットのコインは、それぞれ以下の条件でロックされている。

  • to_local:以下のいずれかの条件でアンロック可能
    • OP_CSVによるタイムロック期間が過ぎたら、自身の鍵で使用可能
    • 相手がrevocation keyを知っていれば、相手がすぐに入手可能
  • to_remote:相手のP2WPKHアドレス

to_localスクリプトは、具体的には↓のようなスクリプト

OP_IF
    <revocationpubkey> # 旧状態がブロードキャストされた場合のペナルティ用
OP_ELSE
   `to_self_delay`
    OP_CSV
    OP_DROP
    <local_delayedpubkey>
OP_ENDIF
OP_CHECKSIG

支払いをルーティングする際は、これにHTLCアウトプットが追加される。そしてそれぞれ保持するコミットメントトランザクションについて、相手の署名を持っている。

新しく支払いやルーティングをする場合、新しいコミットメントトランザクションを作成し、古いコミットメントトランザクションで使用したシークレットを相手に明かす。この時、コミットメントトランザクションも新しくなっているので、それに合わせて署名も新たに作ることになる。

つまり、支払いをする=チャネルの状態を更新するためにいは、秘密鍵はオンラインである必要がある。

Fast Forwardプロトコル

Fast Forwardプロトコルでは、コミットメントトランザクションの2つのアウトプットを対称的な構成に変更している。具体的には、to_remoteが単純な相手へのP2WPKHではなくto_localと対称的なスクリプトで構成される↓

  • to_local:以下のいずれかの条件でアンロック可能
    • OP_CSVによるタイムロック期間が過ぎたら、自身の鍵で使用可能
    • 相手がrevocation keyを知っていれば、相手がすぐに入手可能
  • to_remote:以下のいずれかの条件でアンロック可能
    • OP_CSVによるタイムロック期間が過ぎたら、相手の鍵で使用可能
    • 自分が相手のremote penalty claim keyを知っていれば、すぐに入手可能

to_localのロックスクリプトは↓

OP_IF
    # ペナルティ・トランザクション用
    <local_revokepubkey> OP_CHECKSIGVERIFY <remote_penaltyclaimpubkey>
OP_ELSE
    `to_self_delay`
    OP_CSV
    OP_DROP
    <local_delayedpubkey>
OP_ENDIF
OP_CHECKSIG

to_remoteのロックスクリプトは↓

OP_IF
    # ペナルティ・トランザクション用
    <local_revokepubkey> OP_CHECKSIGVERIFY <remote_penaltyclaimpubkey>
OP_ELSE
    `to_self_delay`
    OP_CSV
    OP_DROP
    <remote_delayedpubkey>
 OP_ENDIF
OP_CHECKSIG

どちらも、ペナルティトランザクション用のアンロック条件に、revocation keyに加えてremote penalty claim keyによる署名検証が加えられている。これが↓のFast Forward HTLCトランザクションを有効にするための仕掛け。

Fast Forward HTLCトランザクション

支払いをルーティングする際は、コミットメントトランザクションにHTLCアウトプットを追加するのではなく、Fast Forward HTLCトランザクションを新たに作成する。このトランザクションは、コミットメントトランザクションto_local/to_remoteをインプットとし、HTLCの送金用のアウトプット(このスクリプトは既存のHTLCのスクリプトと同じ)と、お釣り用のアウトプットを持つトランザクションになる。お釣り用のアウトプットは、インプットにしたto_local/to_remoteと同じスクリプトで(鍵だけ更新)、これが送信者にとっては最新の自身の残高(mainアウトプット)になる。

図示すると↓のようなトランザクションフローになる。

f:id:techmedia-think:20210611230720p:plain
Fast Forwardプロトコル

Fast Forward HTLCトランザクションで使用するインプットのアンロック条件は、↑のスクリプトの最初のブランチの条件↓

<local_revokepubkey> OP_CHECKSIGVERIFY <remote_penaltyclaimpubkey>

で、これをアンロックするにはローカルの署名とリモートの署名、2つの署名が必要になる。この内、Fast Forward HTLCトランザクションを作成する際は、送信者側が両方のFast Forward HTLCトランザクションの署名を提供する。受信側は、このトランザクションがブロードキャストされるような状況になるまで署名を生成しなくても良い。具体的には、送信者は自身が持つコミットメントトランザクションについては、local_revokepubkeyを使って署名し、相手が持つコミットメントトランザクションについては、remote_penaltyclaimpubkeyを使って署名し、この2つの署名を受信者ノードに送信する。

そしてその後のHTLC支払いは、作成した最新のFast Forward HTLCトランザクションのアウトプットを使用する新しいFast Forward HTLCトランザクションを作ることになる。

コミットメントトランザクションからHTLCアウトプットを分離するこの構成の狙いは、ルーティング支払いにおいて、コミットメントトランザクションの更新を発生させないことにある。コミットメントトランザクションを更新する場合、両者の署名が必要になるため、両者の秘密鍵は共におンラインでなければならない。

ペイメントチャネルを↑のような構成にすることで、最終受信者の秘密鍵がオフラインでも支払いが受領できるようにしている。ただ、ペナルティトランザクションを作る際は当然秘密鍵が必要であるし、その署名をする期間はto_self_delayよりも速くなければいけない。また、↑のようにHTCLトランザクションのチェーンが構成されるので、一方的なクローズが発生した場合のオンチェーン手数料は既存のプロトコルより増加する。