送信者が受信者の完全な経路を知らなくても支払いやメッセージのルーティングを可能にする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)
は以下の手順でルートをブラインドする。
- 支払いを受信する自身のノードのチャネルまで、ブラインドするホップを選択する(
N(0) <- N(1) ... <- N(r)
とする)。この時、経路内の各ホップのノード/チャネルはアナウンスされたものでもいいし、アナウンスされていないものでもいい。 - ブラインドに使用する一時鍵
E0 = e0 * G
を生成する。 - ブラインドホップの数分=
i = 0..(r - 1)
回、以下の手順で中間ノードのnode_id
のブラインド化とscid
を暗号化するための共有鍵を導出する。- 受信者が生成した一時鍵と中間ノード
N(i)
鍵ペアP(i) = ki * G
を使って共有シークレットss(i) = H(e(i) * P(i)) = H(E(i) * ki)
を計算する。 - 中間ノードの本来の
node_id
(P(i))を共有シークレットを使ってB(i) = HMAC256("blinded_node_id", ss(i)) * P(i)
を計算することで導出する。導出したB(i)
がブラインドされたnode_id
となる。このB(i)
の秘密鍵を知るのは中間ノードのみ。 - 続いて
scid
の暗号化に使用する鍵をrho(i) = HMAC256("rho", ss(i))
を計算することで導出する。 - 次のホップの計算に使用する一時鍵を導出する。
- 秘密鍵は
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_blob
(type
は10
でデータは暗号化されたtlvデータ)を定義する。scid
は↑で算出した暗号化鍵rho(i)
を使ってChaCha20-Poly1305で暗号化されencrypted_blob
にセットされる。(このためhop_payload
はtlv_payload
フォーマットを使用する)
上記のように、ノード情報とチャネル情報は
- 中間ノードの
node_id
である公開鍵に共有シークレットを乗算することでnode_id
をブラインド - 共有シークレットから
scid
を暗号化する鍵を導出し、暗号化しtlv_payload
のencrypted_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
を復号し次のノードに転送するため以下の処理を行う。
- メッセージ extensionのTLVフィールドから一時鍵
E(i)
を抽出。 - 共有シークレット
ss(i) = H(k(i) * E(i))
を計算 encrypted_blob
の復号鍵rho(i) = HMAC256("rho", ss(i))
を導出encrypted_blob
を復号し、転送先のscid
を入手する。- 転送先のノードに必要な次の一時鍵
E(i+1) = H(E(i) || ss(i)) * E(i)
を導出 - 次のノードに送信するオニオンメッセージのextensionのTLVフィールドに導出した
E(i+1)
をセット
受信ノードN(r)
もアンブラインド処理は上記と同様。
以上が匿名化の仕組み。
攻撃手法
受信者によるECDHによる上記のように途中の経路情報をブラインドすることで、受信者に匿名性を提供するのがルートブラインドの機能だが、送信者が手数料とcltvの設定値を調整することで、ブラインドされたノード、チャネル情報をアンブラインドできる可能性についても言及されている。
送信者がルート上のノードに対して少額の手数料を設定して送金を試行することで、ノードの手数料/cltv値を検出し、それをネットワークグラフ内のチャネル情報と比較することで、ブランドされたノード情報をアンブラインドしようとする攻撃手法が挙げられている。こういった攻撃への対応として、無効なHTLCがオファーされた場合に、
- 使い捨ての鍵を生成し、その鍵を使ってダミーのエラーを返す。この場合送信者はこのエラーの内容を復号できず、ルート内のどのノードが起こしたエラーか分からなくなる。
- タイミング攻撃を利用したアンブラインドに対応するため、エラーを返す際にランダムな遅延時間を発生させる。
などの対応が挙げられている。ただし、攻撃手法を完全に無効化するものではない。