Develop with pleasure!

福岡でCloudとかBlockchainとか。

LNの経路情報を秘匿するRoute Blinding

送信者が受信者の完全な経路を知らなくても支払いやメッセージのルーティングを可能にするRoute Blindingの仕様のドラフトが提案されてるので見てみる↓

https://github.com/lightningnetwork/lightning-rfc/blob/route-blinding/proposals/route-blinding.md

Lightning Networkでは通常、送信者が支払いに使用するInvoiceに記載された受信者までの経路を計算する。

↑のRoute blindingは、経路の最後にある任意のホップ数をブラインドすることで、受信者のノードやチャネル情報を明かすことなく支払いを受けられるようにする、受信者に匿名性を提供するための仕組み。

経路のブラインド

ノード情報(node_id)とチャネル情報(scid(short channel id))は受信者と各中間ノードとのECDHを利用してブラインドされる。

ブラインドする受信者のノードをN(r)とすると、受信者N(r)は以下の手順でルートをブラインドする。

  1. 支払いを受信する自身のノードのチャネルまで、ブラインドするホップを選択する(N(0) <- N(1) ... <- N(r)とする)。この時、経路内の各ホップのノード/チャネルはアナウンスされたものでもいいし、アナウンスされていないものでもいい。
  2. ブラインドに使用する一時鍵E0 = e0 * Gを生成する。
  3. ブラインドホップの数分=i = 0..(r - 1)回、以下の手順で中間ノードのnode_idのブラインド化とscidを暗号化するための共有鍵を導出する。
    1. 受信者が生成した一時鍵と中間ノードN(i)鍵ペアP(i) = ki * Gを使って共有シークレットss(i) = H(e(i) * P(i)) = H(E(i) * ki)を計算する。
    2. 中間ノードの本来のnode_id(P(i))を共有シークレットを使ってB(i) = HMAC256("blinded_node_id", ss(i)) * P(i)を計算することで導出する。導出したB(i)がブラインドされたnode_idとなる。このB(i)秘密鍵を知るのは中間ノードのみ。
    3. 続いてscidの暗号化に使用する鍵をrho(i) = HMAC256("rho", ss(i))を計算することで導出する。
    4. 次のホップの計算に使用する一時鍵を導出する。
      • 秘密鍵e(i+1) = H(E(i) || ss(i)) * e(i)
      • 公開鍵はE(i+1) = H(E(i) || ss(i)) * E(i)

通常hop_dadtaに含まれるscidを暗号化してペイロードにセットするため、tlv_payloadに新しいTLVフィールドencrypted_blobtype10でデータは暗号化されたtlvデータ)を定義する。scidは↑で算出した暗号化鍵rho(i)を使ってChaCha20-Poly1305で暗号化されencrypted_blobにセットされる。(このためhop_payloadtlv_payloadフォーマットを使用する)

上記のように、ノード情報とチャネル情報は

  • 中間ノードのnode_idである公開鍵に共有シークレットを乗算することでnode_idをブラインド
  • 共有シークレットからscidを暗号化する鍵を導出し、暗号化しtlv_payloadencrypted_blobにセット

することでブラインドされる。

受信者は、各ブラインホップの

  • ブラインドされたnode_id
  • 手数料
  • cltv
  • encrypted_blob

データから経路情報を構成し、ブラインドルートとする。尚、ブラインドルートの最初のノードN(0)node_idはブラインドされず、P(0)のまま。

このブラインドルートの情報と最初の一時鍵の公開鍵E(0)インボイスで送信者に伝える。

ブラインドノードへの送信

ブラインドルートを受け取った送信者はブラインドルートの先頭N(0)までの経路を算出する。N(0)node_idはブラインドされていない(P(0)のまま)ので、通常通り算出できる。算出した経路のオニオンペイロードを作成しブラインドルートで拡張する。この時、N(0)のオニオンペイロードE(0)encrypted_blob(0)の値をセットする。

N(0)ペイロードを復号しE(0)encrypted_blob(0)を入手する。続いて、E(0)を使って共有シークレットss(0)を導出し、それを使ってrho(0)を導出し、encrypted_blob(0)を復号し、scidを入手する。転送先が分かったらオニオンメッセージのextensionのTLVフィールドにE(1) = H(E(0) || ss(0)) * E(0)をセットして転送する。

ブラインドルの中間ノードの処理

ブラインドルートの各中間ノードN(1) <- ... <- N(r-1)は、次の転送先ノードについて知るため、次のノードのnode_idをアンブラインドし、encrypted_blob内のscidを復号し次のノードに転送するため以下の処理を行う。

  1. メッセージ extensionのTLVフィールドから一時鍵E(i)を抽出。
  2. 共有シークレットss(i) = H(k(i) * E(i))を計算
  3. encrypted_blobの復号鍵rho(i) = HMAC256("rho", ss(i))を導出
  4. encrypted_blobを復号し、転送先のscidを入手する。
  5. 転送先のノードに必要な次の一時鍵E(i+1) = H(E(i) || ss(i)) * E(i)を導出
  6. 次のノードに送信するオニオンメッセージのextensionのTLVフィールドに導出したE(i+1)をセット

受信ノードN(r)もアンブラインド処理は上記と同様。

以上が匿名化の仕組み。

攻撃手法

受信者によるECDHによる上記のように途中の経路情報をブラインドすることで、受信者に匿名性を提供するのがルートブラインドの機能だが、送信者が手数料とcltvの設定値を調整することで、ブラインドされたノード、チャネル情報をアンブラインドできる可能性についても言及されている。

送信者がルート上のノードに対して少額の手数料を設定して送金を試行することで、ノードの手数料/cltv値を検出し、それをネットワークグラフ内のチャネル情報と比較することで、ブランドされたノード情報をアンブラインドしようとする攻撃手法が挙げられている。こういった攻撃への対応として、無効なHTLCがオファーされた場合に、

  • 使い捨ての鍵を生成し、その鍵を使ってダミーのエラーを返す。この場合送信者はこのエラーの内容を復号できず、ルート内のどのノードが起こしたエラーか分からなくなる。
  • タイミング攻撃を利用したアンブラインドに対応するため、エラーを返す際にランダムな遅延時間を発生させる。

などの対応が挙げられている。ただし、攻撃手法を完全に無効化するものではない。