Develop with pleasure!

福岡でCloudとかBlockchainとか。

LNの強化:コントラクト違反時の防衛強化とSigned Sequence Commitment

Lightning Networkのセキュリティ強化およびクライアントをよりスケーラブルにするための強化案について@roasbeef ‏がBPASE 2018で発表した内容↓(スライドトランスクリプト)について見てみる。

www.youtube.com

トピックとしては

  • コントラクトの違反が発生した場合の防衛強化
  • LNクライアントの履歴データの削減
  • Covenantsを利用したHTLCの改善
  • マルチパーティチャネル
  • 手数料のコントロール

まずこの内の先頭2つについて、どういうものかまとめてみた。

コントラクトの違反が発生した場合の防衛戦略の強化

LNのコミットメントトランザクションには古いトランザクションをブロードキャストする不正が行われた場合に、不正を行った相手の資金を没収するトランザクションを作成しブロードキャストすることができる。このため、不正を働くインセンティブをなくしている。

この仕組みは、コミットメントトランザクションをブロードキャストした際に、ブロードキャストした側がコインを入手するには、そのトランザクションがブロックに格納されて指定ブロック数待つ必要があり、その間にそのコミットメントトランザクションを作成した際に使用したシークレットが分かれば相手がそのコインを入手できるというコントラクトによって成立している。

この場合、不正を働かれたユーザーは、古いコミットメントトランザクションがブロックに格納されてから指定ブロック数までの間に資金を取り戻すトランザクションをブロードキャストし、ブロックに入れられなければならない。ただメモリプールのトランザクションがいっぱいで混雑している場合、必ずしも資金を取り戻すためのトランザクションが先にブロックに入るという保証はなく、ひょっとすると指定されたタイムロック期間までにブロックに入ることなく不正を働いた側のトランザクションが先にブロックに入ってしまうという可能性も考えられなくはない。

↑のプレゼンテーションで@roasbeefが提案してるのは、こういうケースの防衛のため、不正を働いたユーザーのコインを取引相手が没収するのではなく、不正を働いたユーザーの残高をそっくりそのままマイナーへの手数料へ加えてしまおうという提案。

誰かが古い状態のコミットメントトランザクションをブロードキャストしようとすると、トランザクションはその特定の状態にロックされる。例えば、ボブの最新の残高は$2で、以前の残高が$10だったとして、ボブは$10の状態に戻そうとする場合。取引相手は古い自分の残高についてはすぐに入手でき、ボブはトランザクションがブロックに格納されてから指定されたブロック分待つと$10入手できる。ただこれは不正行為なので、取引相手はシークレットを使って$10のアウトプットをすぐに入手しようと試みる。この時タイムロックはされているとはいえ、ボブより早く取引相手の作ったトランザクションがブロックに取り込まれる必要がある。問題となるケースは、ブロックが混雑していて、取引相手の作成したトランザクションがなかなかブロックに入れられずタイムロックの期間が過ぎてしまうようなケースだ。この場合取引相手が取る戦略として、$10のアウトプットのボブの取り分をマイナーへの手数料へ回す。実際に前の状態のコミットメントトランザクションをブロックに入れることにボブが成功する唯一のケースは、ブロックが混雑していて、取引相手がボブの残高をそのまま手数料にするのを考慮すると、ボブの残高より高い手数料をマイナーに支払う場合になる。これはボブにとって何の得にもならないケースだ。このため、例え大量にトランザクションが詰まっていたとしてもマイナーがより高い手数料を求める傾向があれば、ボブは何も手にすることはなくなるだろうと。

各クライアントの履歴データの削減

LNでチャネルをオープンしオフチェーン決済をする際は、毎回オンチェーン上のマルチシグにロックした資金の残高を決済額に応じて更新するコミットメントトランザクションを作成し、前に作成したコミットメントがブロードキャストされないよう、前のコミットメントトランザクションのシークレットを交換するステップを踏む。チャネルをクローズする際はチャネルの最終残高を二者のアドレスに送付するクロージングトランザクションを協力して作成するため、このコミットメントトランザクションがブロードキャストされることはない。コミットメントトランザクションがブロードキャストされるケースは、相手と連絡がつかなくなった場合で、その時チャネルをクローズするのに使われる。

また相手が自分に有利な過去のコミットメントトランザクションをブロードキャストしようとする不正を働くケースに対応するため、交換したシークレットや相手の署名データは全て保存しておかなければならない。

現在、古い状態のトランザクションを取り消すのに使っているのがRevocation Keyを使うアプローチ↓

techmedia-think.hatenablog.com

オフチェーン決済によって高速で安価に決済ができるようになるのはLNメリットで、効率的な意味でもそういったペイメントチャネルのライフタイムが長くなることが望ましいが、その分、ローカルで各決済の状態遷移をずっと管理しておく必要があり、決済の数に比例してストレージコストも増える。そこでコミットメントの無効化の仕組みを改善しようというのが今回の提案↓

Signed Sequence Commitment

今回提案されている新しいコミットメントの無効化の方法がSigned Sequence Commitmentと呼ばれる方法。

今までの無効化のアプローチは、状態を更新する(オフチェーン決済をする)際に前のコミットメントトランザクションで使用していたRevocation Keyを相手に明らかにする方法をとっていたけど、Signed Sequence Commitmentでは

  • 各状態(オフチェーン決済)にステートナンバーを割り当てる。
  • ステートナンバーにコミットするコミットメントを作成する。

状態を更新する(新しい決済をする)際には、以下の処理を行う。

  1. 前の状態のコミットメントを開く。
  2. コミットメントを(今までのRevocation Keyの代わり)に、新しいオフチェーン決済トランザクションのアウトプットスクリプトに入れる。
  3. ステートナンバーをインクリメントした新しいコミットメントを作成する。
  4. 生成した新しいコミットメントに両者の鍵で署名をする(この時の署名は集約署名にするみたい。具体的な署名形式は話されてない。)

取引相手が不正をして前の状態のトランザクションをブロードキャストした場合は、そのトランザクションのステートナンバーより、大きなステートナンバーへのコミットメントの有効な署名を提供することで(Revocation Keyの代わりに)、相手の資金を入手できるようにする。

Signed Sequence Commitmentでは、最新のステートナンバーへのコミットメントの有効な署名があれば、過去の状態のどんなコミットメントトランザクションがブロードキャストされても、その署名のみで不正を無効化することができるようになる。これにより、今まで過去の決済数分のRevocation Keyをローカルストレージに保持しなければならなかったのが、最新の署名データのみをローカルストレージに保存しておけばよくなる。

ただ、これを実現するためには、ステートナンバーへのコミットメントに対する署名検証(任意のデータに対する署名検証)が必要になる。現在Bitcoinには任意のデータに対する署名検証を行うopcodeは無いので、↑のスライドでも紹介されているOP_CHECKSIGFROMSTACK*1が必要になり、そのスクリプトの導入を提案している。

LNに限らず、外部オラクルを利用したコントラクトの作成もできるので、任意のデータに対して署名検証する仕組みは欲しいなー。

*1:Blockstreamが提供するサイドチェーンElementsで実装されている、スタック上のアイテム(公開鍵、メッセージ、署名データ)の署名検証をするopcode。