Lightning Network · BOLT #02 #04 #05 #11 #12 · End-to-end

Anatomy of a Lightning Payment
Invoice から Settlement まで 1 回の支払いを徹底解剖

bolt11:lnbc... という invoice 文字列から始まり、Sphinx onion でホップを暗号化し、HTLC をマルチホップでカスケード、 preimage の逆伝搬で atomically settle するまで。1 つの支払いが LN ネットワークを通り抜ける全工程を可視化する。 失敗ケース・blinded paths・MPP・trampoline まで網羅。

対象 BOLT#02 / #04 / #05 / #07 / #11 / #12
所要時間通常 <1秒 (3-5 hops)
Onion size1300 bytes (固定)
AtomicityHash preimage / PTLC adaptor sig
11 BOLTs
touched per payment
1300 B
onion packet (fixed)
<1 s
typical settlement
Atomic
all-or-nothing across N hops
§ 1 · Overview — The 4 Phases

1 つの支払いが通り抜ける 4 つのフェーズ

Alice (sender) が Dave (recipient) に 10,000 sats を送る最小ケースを追う。Bob と Carol が中継ホップ。

Alice Bob Carol Dave HTLC: 10,002 sats HTLC: 10,001 sats HTLC: 10,000 sats preimage R preimage R preimage R ①② Invoice + Pathfinding Sender resolves invoice, builds onion ③ HTLC Cascade → commit_signed each hop ④ Preimage Cascade ← update_fulfill_htlc Each hop earns a small fee · CLTV decrements at each hop · Atomic via shared preimage R

Phase 1-2: Sender 側

  1. Invoice 解決: Dave が lnbc100u1p... を発行、Alice が解読
  2. Pathfinding: Alice が gossip graph から最適経路を選択
  3. Onion 構築: 各ホップ宛のペイロードを Sphinx で多層暗号化

Phase 3: HTLC Forward

  1. update_add_htlc (BOLT #2)
  2. commitment_signed + revoke_and_ack
  3. 各ホップ: fee 控除 / CLTV decrement
  4. すべてのホップで条件成立 → Dave が preimage 開示準備

Phase 4: Preimage Cascade

  1. update_fulfill_htlc が逆方向にカスケード
  2. 各ホップで HTLC が settled → fee 確定
  3. Atomicity: 同じ preimage R が全ホップで作用
  4. Alice が R を受信した瞬間に決済完了

失敗ケース

  1. update_fail_htlc: onion-encrypted error 逆カスケード
  2. Stuck HTLC: peer がオフライン → timeout 待ち
  3. Force-close 中の sweep: BOLT #5 timing
  4. Wormhole: 中間者が honest hop をスキップ
§ 2 · Invoice (BOLT #11)

支払いの入口 — bolt11 invoice の解読

Lightning の支払いは通常、受信者が発行する invoice 文字列(bech32 エンコード)から始まる。 lnbc プレフィックス、額、payment_hash、有効期限、payee node id、route hints、機能フラグなどを含む。

Sample bolt11 invoice

lnbc100u1p3xnhl2pp5jptserfk3zk4qy42tlucycrfwxhydvlemu9pqr93tuzlv9cc7g3sdqsvfhkcap3xyhx7un8cqzpgxqyz5vqsp5vl4zmuvhl8rzy4rpwtxazlrf5ksrcjpmsfp7jc83yh82e83zqgs9qyyssqdfjycqr0wqu6kmu8j7vncn07pq6lkzsrunhxn04m8wqxh8z9z9hyyqjcyq6q4l3sjps...

なぜ payment_hash で preimage を隠せるか

SHA256 は preimage resistance を持つ。Dave は R をランダム生成し H = SHA256(R) を invoice に埋める。 経路上のすべてのノードは H を見るが、R を導出することは(暗号学的に)不可能。 Dave だけが R を知っているため、最終的に Dave が R を開示することで支払いが atomic にロック解除される。

# Dave invoice 発行 R = random_32_bytes() H = sha256(R) invoice = bolt11_encode(amount=10000, payment_hash=H, ...) # Alice 受信 parsed = bolt11_decode(invoice) target_node = parsed.payee_node_id amount = parsed.amount hash = parsed.payment_hash # H, but not R
§ 3 · Path Selection (Pathfinding)

Gossip graph から経路を選ぶ

Alice はネットワークの gossip graph(BOLT #07 channel_announcement / channel_update から構築)を持っている。 Dave への経路を Dijkstra / Pickhardt MCF で探索し、fee と success probability のトレードオフを最適化する。

Click to start pathfinding
Alice Bob Eve Carol Frank Dave 1+10ppm 2+50ppm 1+10ppm 5+200ppm 3+30ppm 1+10ppm 1+10ppm 10+500ppm

Selected Path:

経路選択を開始すると詳細が表示されます。

Fee + CLTV の累積計算

送信者は 逆方向に fee と CLTV を組み立てる: 「最終ホップで dest_amount を受け取るには、各ホップで何 sats / 何ブロックの CLTV が必要か」。

# Alice → Bob → Carol → Dave for 10,000 sats final, min_final_cltv = 18 | amount | cltv_delta | accumulated_cltv Dave (final) | 10,000 | 18 | block_height + 18 Carol → Dave | 10,001 (1+10ppm fee) | 40 | block_height + 18 + 40 Bob → Carol | 10,002 (1+10ppm fee) | 40 | block_height + 18 + 40 + 40 Alice → Bob | 10,002 | — | block_height + 18 + 40 + 40 # Alice locks 10,002 sats, expects them confirmed at the final block_height + 98

Pathfinding アルゴリズム

AlgorithmCost functionProbability実装
Dijkstra (legacy)Σ fee無視初期 LND
LND probability-costΣ (fee + α · risk)独立 priorLND v0.13+
Pickhardt MCFmin Σ −log(P_success)min-cost flowBLW、CLN プラグイン
SpeedyMurmursspanning-tree basedlandmark研究のみ
§ 4 · Onion Construction (Sphinx)

各ホップを多層暗号化する Sphinx パケット

Alice は BOLT #04 Sphinx 形式で 1300-byte 固定長パケットを構築する。各ホップは 自分の層だけ復号でき、 内部に「次のホップ ID と転送額・CLTV」が含まれる。中間ホップは 送信者・受信者・パス長のいずれも知らない。

Onion Peel — クリックで層を剥がす

Layer 1 — for Bob

next: Carol · amt: 10,001 sats · cltv: H+58 · HMAC: 0x4f...

Layer 2 — for Carol

next: Dave · amt: 10,000 sats · cltv: H+18 · HMAC: 0x9c...

Layer 3 — for Dave

amt: 10,000 sats · payment_secret: 0xvl4z... · I am the recipient

Innermost — Payload

payment_hash: H = SHA256(R) (already known)

各層を順にクリックするか「Peel All」で全層を剥がす。

Sphinx パケットの構造

# Sphinx packet (BOLT #04) { version: 0x00, # 1 byte public_key: ephemeral_pubkey, # 33 bytes (sender's per-hop key) hops_data: [ # 1300 bytes - ALWAYS 1300 (padded) , # for Bob: encrypted , # for Carol: encrypted , # for Dave: encrypted # conceals path length ], hmac: 0xabcd... # 32 bytes - HMAC chain } # Total: 1366 bytes # Each hop: derive shared_secret = ECDH(my_priv, ephemeral_pub) # decrypt my_payload, verify HMAC, blind ephemeral_pub for next hop

Sphinx の暗号学的性質

送信者匿名性

中間ノードは onion 経由で alice の identity を知らない。pubkey は ephemeral.

受信者匿名性

中間ノードは Dave が最終受信者であることを知らない(更にホップがあるかも).

パス長秘匿

1300 byte 固定長 + random padding により、ホップ数が漏れない.

HMAC チェーン

各ホップで HMAC を更新。改竄は次のホップで検出される.

限界と既知の攻撃

§ 5 · HTLC Cascade (Forward)

BOLT #2 メッセージで HTLC が前方カスケード

Alice → Bob → Carol → Dave の各ホップで update_add_htlc → commitment_signed → revoke_and_ack という 3 メッセージのラウンドトリップが起きる。 これにより各ホップ間のチャネル commitment が更新され、HTLC が「保留」状態でロックされる。

Hop 0 / 3
Alice → Bob ━━ HTLC ━━▶ 10,002 sats pending
Bob → Carol ━━ HTLC ━━▶ 10,001 sats pending
Carol → Dave ━━ HTLC ━━▶ 10,000 sats pending
Press Play to start the HTLC cascade.

各ホップで起きる BOLT #2 メッセージ

# Alice → Bob (per-hop) Alice → Bob: update_add_htlc(htlc_id=42, amt=10002, payment_hash=H, cltv=H+98, onion=...) Alice → Bob: commitment_signed(new_commit_sig, htlc_sigs) # commit new state Bob → Alice: revoke_and_ack(revocation_secret_old, next_per_commit_pt) Bob → Alice: commitment_signed(new_commit_sig, htlc_sigs) # Bob's view too Alice → Bob: revoke_and_ack(revocation_secret_old, next_per_commit_pt) # Now both have a new commitment with the HTLC added # Bob holds 10,002 sats LOCKED in HTLC

commitment_signed の中身

各ホップは新しい commitment TX に署名する。これは 古い state を放送すれば全額没収される設計(penalty mechanism)。HTLC が加わった新 state を承認する 2 ラウンド trip が必要。

HTLC ロック条件 (Script)

scriptPubKey: OP_IF # preimage path: Bob can claim if he reveals R OP_HASH160 <H> OP_EQUALVERIFY <Bob_pubkey> OP_CHECKSIG OP_ELSE # refund path: Alice reclaims after timeout <cltv> OP_CHECKLOCKTIMEVERIFY OP_DROP <Alice_pubkey> OP_CHECKSIG OP_ENDIF

重要な数値

  • cltv_expiry_delta: 各ホップで CLTV が減少する量(典型的 40 blocks)
  • fee: base_fee_msat + amt × fee_rate_ppm
  • 483: BOLT 仕様での pending HTLC 上限/方向(jamming attack の根拠)
  • min_final_cltv_expiry: invoice で受信者が指定(最終ホップの buffer)
§ 6 · Settlement — Preimage Cascade

Dave が R を開示 → 逆方向に decree が遡る

最終ホップ Carol → Dave の HTLC が成立した時点で、Dave は preimage R(H = SHA256(R) の元)を持っている。 Dave が R を Carol に渡す(update_fulfill_htlc)と、Carol は HTLC を unlock し、自身も R を Bob に渡す。 これが Alice まで 逆方向に cascade することで全 HTLC が atomic に settled される。

Dave → Carol ◀━ R 開示 ━━ +10,000 → Dave locked
Carol → Bob ◀━ R forward ━━ +1 fee → Carol locked
Bob → Alice ◀━ R forward ━━ +1 fee → Bob locked
Press Play to release the preimage cascade.

BOLT #2 メッセージ

# Dave receives the HTLC, has R Dave → Carol: update_fulfill_htlc(htlc_id, payment_preimage=R) Dave → Carol: commitment_signed(...) # commit removal of HTLC Carol → Dave : revoke_and_ack(...) Carol → Dave : commitment_signed(...) Dave → Carol: revoke_and_ack(...) # Now Dave holds 10,000 sats outright # Carol immediately forwards R to Bob Carol → Bob : update_fulfill_htlc(htlc_id, payment_preimage=R) ... # same dance # Carol earns 1 sat fee # Eventually Alice receives R via Bob # Alice's wallet: payment proven settled (R is the receipt)

なぜ atomic か

同一の preimage R がすべてのホップで使われている。Dave が R を開示した瞬間、すべてのホップで preimage path が解錠可能になる。 もし Carol が「Bob に R を渡さない」を選んでも、Bob は on-chain で HTLC を closed し、R を直接観測して preimage path を行使できる(HTLC sweep TX)。 これにより atomicity は protocol レベル + on-chain enforcement の二重で保証される。

支払い完了の証拠 — preimage R

R は 支払いの receipt として機能する。merchant は R を保管することで「この payment_hash の支払いが完了した」を非対話的に証明できる。 これは BOLT 12 でより強化された (signed invoice)。

§ 7 · Failure Modes

支払いが失敗するパターンと逆 cascade

A

update_fail_htlc — 通常失敗

中間ホップで失敗(流動性不足、信号不通など)。エラーが onion-encrypted で逆カスケード。各ホップでさらに encrypt されるため、誰がエラーを発生させたかはみえる、具体的理由はみえない。

B

Stuck HTLC — peer offline

ホップの片方がオフラインになった場合、そのホップの HTLC は CLTV expiry まで stuck。受信者の preimage 開示も中継できない。最悪 force-close で on-chain 解決。

C

Force-close 中の sweep — BOLT #5

HTLC 保留中にチャネルが force-close されると、HTLC sweep TX を時間内(CLTV)に on-chain 提出する必要がある。
Replacement Cycling 攻撃 (2023) はここを突く。

D

Wormhole 攻撃

共謀 attacker が経路上で honest 中間ホップを skipし、Bob と Carol を出し抜いて fee を独占する。HTLC の同一 preimage 性に起因。
PTLC で解決可能

onion-encrypted error の cascade

Alice Bob Carol⚠ failure Dave enc(failure_msg, key_carol) enc(enc(failure_msg, k_carol), k_bob) Each hop encrypts with its own shared_secret. Only Alice can fully decrypt.

Replacement Cycling Attack (2023 disclosure)

2023 年 10 月に Antoine Riard が公開した Replacement Cycling Attack。攻撃者は HTLC-Success と HTLC-Timeout を交互に mempool replacement することで、honest party の sweep TX を mempool から evict させる。 被害者が CLTV expiry までに sweep を含められなければ HTLC を失う。

対策: 全 LN 実装 (lnd / eclair / ldk) が patch リリース。根本解決は Bitcoin core 側の v3-transactions (TRUC)package relay (BIP331) 等の mempool ポリシー改善に依存。

Wormhole 攻撃の構造

# 共謀: Alice ←→ Bob ←→ Carol ←→ Dave ←→ Eve # Bob と Eve が共謀 正常フロー: Alice → Bob → Carol → Dave → Eve fee: Alice 払う, 各 Bob/Carol/Dave が分け取る Wormhole: 1. Bob は HTLC を Carol に通常転送(preimage hash H) 2. Eve は Dave に payment_hash を渡されるが、preimage R を直接 Bob にバイパス通知 3. Bob は Alice に R を返し、Alice の HTLC を解錠 → Alice 払い完了 4. Carol/Dave の HTLC は CLTV まで stuck → 自動 timeout → Bob と Eve が Carol/Dave の fee を奪取 PTLC (BIP-340 Schnorr + adaptor sig) では各ホップで異なる lock を使うため wormhole が成立しない (各ホップ間の preimage が共通でない).
§ 8 · Blinded Paths (BOLT #04 / #12)

受信者の identity を隠す

BOLT #12 (offers) で導入された blinded paths。受信者が予め blinded route(複数のホップを暗号で blind した経路)を提供し、送信者はそれを onion の末尾に埋めて支払う。 送信者は 受信者の node_id を学習しない

Alice sender Bob introduction node 🌫 Blinded zone (Alice cannot see) N1 N2 Dave visible blinded scid

標準 onion vs blinded path

性質標準 onionblinded path
Sender knows recipientYESNO
Receiver gossip requiredNONO (blinded scids)
Private channels supportedpartial (route hints)YES
SpecBOLT #04BOLT #04 update + #12
Implementationalleclair / cln / lnd partial

暗号メカニズム

受信者は blinding factor の連鎖で各 blinded ホップの ephemeral pubkey を導出。送信者は introduction node までは通常の onion で到達し、 その後は受信者が事前計算した blinded onion fragment が逐次復号される。

§ 9 · MPP — Multi-Path Payments

1 つの支払いを複数の経路に分割

流動性の制約を超えるために、1 つの支払い(同一 payment_hash)を 複数のフラグメントに分割し、それぞれ異なる経路で送る。 すべてのフラグメントが受信側で揃った時点で atomic に settle される。

Total: 0 / 100,000 sats
Fragment 1
25,000 sats
pending
Fragment 2
25,000 sats
pending
Fragment 3
30,000 sats
pending
Fragment 4
20,000 sats
pending
Press Play. Each fragment travels independently and only settles when all arrive.

onion payload での識別

# Each fragment's final hop payload (BOLT #4 final_payload) { amt_to_forward: 25_000, # this fragment's amount outgoing_cltv_value: H+18, payment_data: { payment_secret: 0xvl4z..., # MUST match invoice's secret (defend payee probing) total_msat: 100_000_000 # total payment expected (msat) } } # Receiver waits until Σ amt_to_forward reaches total_msat # Then reveals R atomically (or fails all if any fragment doesn't arrive in time)

✅ MPP の利点

  • 個別チャネル容量を超える支払いが可能
  • Pickhardt MCF と組み合わせて success probability 最大化
  • fragment レベルで失敗 → retry 可能

⚠ MPP の課題

  • 受信者が all-or-nothing でロック → fragment stuck で全体停止
  • 各 fragment が独立 onion → fee コストが N 倍
  • payment_secret 必須(MPP のための spec 拡張)

Adaptive Multi-Path / Boomerang

MPP の拡張として Boomerang や AMP(v0 atomic-mpp)など複数の派生がある。Boomerang は redundant fragments を送り、必要数が到達した時点で settle、余剰は refund する。 LN mainnet では基本的な MPP が deploy されており、AMP は spotlight 上にあるが採用は限定的。

§ 10 · Trampoline Routing

軽量クライアント向けの 2 段ルーティング

モバイルウォレットは LN gossip graph 全体を持てない(数百 MB 以上)。Trampoline routing は、送信者が trampoline node を信頼し、 その node に「ここから先は適当にルーティングしてくれ」と inner onion を渡す方式。

📱 Alicemobile (no gossip) 🛏️ TTrampoline Inner routes (T figures out) N1 N2 N3 Dave outer onion includes inner

Onion 構造 — outer / inner

Outer onion (Alice → Trampoline T): next: T payload: { amt_to_forward: 10_002, cltv: H+98, inner_onion: (encrypted with T's key) } Inner onion (T expands to: T → N1 → N2 → N3 → Dave): payload: { final_destination: Dave, amt: 10_000, cltv: H+18 } # T constructs the inner Sphinx packet for the actual N1→N2→N3→Dave route # Alice trusts T to route honestly

利点

  • モバイルクライアントが gossip graph 不要
  • Source pathfinding コスト削減
  • BOLT 12 と組み合わせるとより強力

トレードオフ

  • Trampoline node に依存(信頼ではないが routing 失敗のリスク)
  • Trampoline node は trampoline-aware である必要
  • Eclair と CLN にあり、LND は historically 未対応
§ 11 · Resources & Related Pages

関連する HTML / wiki / spec

本サイト内のビジュアル解説

主要 BOLT リファレンス

  • 📜 BOLT #02 — Peer Protocol (update_add_htlc / commitment_signed / revoke_and_ack)
  • 📜 BOLT #03 — Bitcoin Transaction & Script Formats (HTLC scripts)
  • 📜 BOLT #04 — Onion Routing Protocol (Sphinx)
  • 📜 BOLT #05 — Recommendations for On-chain Transaction Handling
  • 📜 BOLT #07 — P2P Node and Channel Discovery (Gossip)
  • 📜 BOLT #11 — Invoice Protocol for LN
  • 📜 BOLT #12 — Offers and Blinded Paths

関連論文

  • 📄 Heilman et al.Counting Down Thunder: Timing Attacks on LN FC 2020
  • 📄 Malavolta et al.AMHL: Anonymous Multi-Hop Locks for Blockchain Transactions NDSS 2019
  • 📄 Pickhardt & RichterOptimally Reliable Routing in Payment Channel Networks arXiv 2021
  • 📄 Avarikioti et al.Wormhole Attacks in Payment Channel Networks USENIX Sec '20
  • 📄 Riard 2023 disclosure — Replacement Cycling Attack on LN HTLCs