The Problem — Payment Correlation

Without special cryptography, intermediate routing nodes can trivially identify that they are forwarding the same payment — breaking sender/receiver privacy.

Naive HTLC Route

Each hop receives the same payment hash H. Since H is deterministic and identical, any two colluding nodes can confirm they're on the same payment path.

Alice Bob H = a3f9…
Bob Carol H = a3f9…
Carol Dave H = a3f9…
Payment Correlation Attack
  • Bob and Carol collude
  • Both see hash H = a3f9…
  • Same H → same payment!
  • They infer: Alice → Dave, amount ~X sats
  • Sender and receiver deanonymized
Why this matters

Even with onion routing (source routing), the payment hash leaks correlation between hops. Any two nodes on the path — even non-adjacent — can link payments to a single sender.

Animated: Colluding Nodes Detect Correlation

Click the button to watch Bob and Carol compare notes and detect the same payment hash.

Alice Bob H = a3f9b2c1
Bob Carol H = a3f9b2c1
Carol Dave H = a3f9b2c1
🔍 Bob & Carol collude: "We both forwarded H = a3f9b2c1 — it's the same payment! Alice is paying Dave."
Key Problem
Payment hash H is a global identifier — it links all hops of a single payment. This is the fundamental privacy flaw that PTLC and Adaptor Signatures solve by making each hop's "lock value" unlinkable.
HTLC — Hash Time-Locked Contracts

Step through a 3-hop payment Alice → Bob → Carol → Dave. HTLC binds payment to a hash preimage with timelocks.

1
Setup: Alice creates the secret
AMHL — Anonymous Multi-Hop Locks

The key insight: give each hop a different lock value, but ensure a single key can satisfy all of them. This breaks correlation while preserving atomicity.

HTLC Problem: Same Lock Everywhere
Alice→Boblock = H
Bob→Carollock = H
Carol→Davelock = H

Three identical locks → trivially correlated.

AMHL Fix: Different Locks, Same Key Structure
Alice→Boblock = z₀
Bob→Carollock = z₁
Carol→Davelock = z₂

Three different locks → no correlation!

The Math: Additive Key Derivation

Alice picks secret scalar r and random blinding factors α₁, α₂.

z₀ = r ← Alice's secret (also claim key for last hop) z₁ = r + α₁ ← Bob's lock (given to Bob encrypted) z₂ = r + α₁ + α₂ ← Carol's lock

Each hop is given: "reveal zᵢ₊₁ to unlock; I will give you zᵢ back".

When Dave reveals r:

  • Carol learns r → computes z₁ = r + α₁ → unlocks from Bob
  • Bob learns z₁ → computes z₀ = r → unlocks from Alice
Animated: AMHL Unlock Propagation

Watch how the secret propagates backward with each hop learning a different value.

🔒
Alice → Bob
Lock: z₀ = r
waiting…
🔒
Bob → Carol
Lock: z₁ = r + α₁
waiting…
🔒
Carol → Dave
Lock: z₂ = r + α₁ + α₂
waiting…
Key Insight
The locks z₀, z₁, z₂ are computationally unlinkable to an outside observer (each looks random). Yet they are algebraically linked: learning r lets each hop derive their predecessor's claim key. This is the foundation of PTLC.
PTLC — Point Time-Locked Contracts

PTLCs replace hash-based locks with elliptic curve point locks, enabling cryptographic unlinking across hops and scriptless on-chain footprints.

HTLC — Hash-Based
SecretPreimage R (random bytes)
LockH = SHA256(R)
Unlock conditionReveal R such that SHA256(R) = H
Privacy❌ Same H on every hop
ScriptOP_SHA256 H OP_EQUALVERIFY
RequiresSegWit + Bitcoin Script
Script (P2WSH)
OP_DUP OP_HASH160 <BobPKH> OP_EQUALVERIFY OP_CHECKSIG OP_SHA256 <H> OP_EQUALVERIFY OP_CHECKSIG // OR (timeout path): OP_CHECKLOCKTIMEVERIFY OP_DROP OP_CHECKSIG
Privacy Issues
  • Hash H is visible on-chain in scripts
  • H is the same for all hops off-chain
  • Correlatable by any observer
  • Script reveals payment type

Side-by-Side: What Nodes See
Property HTLC PTLC
Hop lock value Same H everywhere Different Tᵢ per hop
On-chain reveal Preimage R in Script Adaptor sig completes → s extracted off-chain
Script complexity Complex P2WSH script Simple key-path Taproot
Payment correlation ❌ Possible ✅ Prevented
Wormhole attack ❌ Vulnerable ✅ Prevented
Lightning status ✅ Deployed (BOLT#3) ⏳ Spec drafted, not deployed
Why Schnorr?
Schnorr signatures are linear: σ₁ + σ₂ = σ₁₊₂. This linearity allows adaptor signatures to work — you can "complete" a partial signature by adding a secret scalar. ECDSA (used in legacy Bitcoin) does not have this property. Taproot (BIP341) enabled Schnorr on Bitcoin, making PTLCs feasible.
Adaptor Signatures — Step by Step

An adaptor signature is a "pre-signature" that becomes valid only when a secret scalar is revealed — binding cryptographic secrets to digital signatures.

Setup

Alice wants to pay Bob conditional on Bob knowing scalar s, where S = s·G is the corresponding public point.

S = s · G    (Bob's secret s, public lock point S)

Alice knows S but not s. She uses an adaptor signature so that when Bob reveals s, Alice can extract it from the signature.

1️⃣
Bob creates adaptor signature σ̃
σ̃ = (k − s) mod n   // k = nonce, using Bob's private key
This is not a valid Schnorr signature yet — it's missing the secret s. Bob sends (σ̃, S) to Alice.
2️⃣
Alice verifies the adaptor
σ̃ · G =? R − S    (where R = k·G)
Alice can check that σ̃ is correctly formed w.r.t. S without knowing s. The verification passes, so she is confident: if Bob reveals s, he gets paid.
3️⃣
Bob reveals s → completes the signature
σ = σ̃ + s    (now a valid Schnorr signature!)
Bob publishes σ on-chain to claim his payment. The signature σ is now valid and accepted by Bitcoin nodes.
4️⃣
Alice extracts s from the published signature
s = σ − σ̃    (Alice learns the secret!)
Alice observes σ on-chain, computes s = σ − σ̃. She now has the secret — no extra communication needed. She can use this to unlock her upstream PTLC.

G S=s·G R=k·G σ̃·G R − S Elliptic curve point operations
Key Insight
Adaptor signatures bind a cryptographic secret to a digital signature.

You learn the secret when the signature is revealed — not before, not separately. This eliminates the need for separate hash revelation in scripts. Everything happens through the signature itself.

Security Properties
Pre-signature hidingσ̃ reveals nothing about s
ExtractabilityGiven σ, σ̃ → s is computable
UnforgeabilityCan't forge valid σ without s
Atomicitys is revealed iff payment succeeds
Scriptless Scripts — Hiding Logic in Signatures

Encode payment conditions inside the signature itself — on-chain, the transaction looks like a simple key-path Taproot spend with no script at all.

Traditional: Script-Based

Payment conditions are encoded in Bitcoin Script opcodes. The script is revealed on-chain when the UTXO is spent.

// HTLC on-chain script reveal: OP_SHA256 <H = a3f9b2c1…> OP_EQUALVERIFY OP_DUP OP_HASH160 <Bob's PKH> OP_EQUALVERIFY OP_CHECKSIG
  • Script is public → reveals payment type
  • Larger witness data → higher fees
  • Payment hash visible to block explorer
  • Distinguishable from regular payments
Scriptless: Signature-Based

The same payment condition is encoded as a relationship between adaptor signatures and a secret point. On-chain: just a Schnorr signature.

// PTLC on-chain spend (Taproot): // witness: <sig> // scriptPubKey: <internal_key> OP_CHECKSIG // The sig encodes the payment secret! // Looks identical to any other Taproot spend.
  • No script revealed on-chain
  • Minimal witness size → lower fees
  • Indistinguishable from regular payment
  • Secret learned off-chain from sig delta
What "Scriptless" Enables
Atomic Swaps
Cross-chain swaps using PTLC adaptor sigs — no hash preimage needed. ETH↔BTC swap with a single curve point.
Discreet Log Contracts
Oracle-based contracts where the oracle's signature acts as an adaptor secret. No script, just signatures.
Lightning PTLCs
Replace HTLC in Lightning channels. Each hop has an unlinkable adaptor secret. Full route privacy.

Full Comparison Table
Property HTLC PTLC (Scriptless)
On-chain tx size Large (P2WSH script path) Small (Taproot key path)
Privacy on-chain Hash visible in script Just a Schnorr signature
Payment correlation Same H all hops Different Tᵢ per hop
Requires SegWit (BIP141) Taproot + Schnorr (BIP340/341)
Lightning status ✅ Active (BOLT#3) ⏳ Spec drafted, not deployed
Wormhole attack ❌ Vulnerable ✅ Prevented
Relative fee Higher (more witness bytes) Lower (key-path spend)
Andrew Poelstra's Insight (2017)
"Scriptless Scripts" was coined by Andrew Poelstra at the 2017 Milan Lightning Hack Day. The key observation: Schnorr's linearity allows payment conditions to be encoded into the signing nonce rather than in Script opcodes — making complex contracts look like simple signatures.
Wormhole Attack — and Why PTLC Fixes It

The wormhole attack lets a node that appears twice on a route skip an intermediate node, stealing fees while the skipped node gets nothing.

HTLC: Wormhole Attack

Route: Alice → Bob → Carol → Bob₂ → Dave. Bob₂ is a second node controlled by Bob. With HTLC, since all hops see the same H, Bob and Bob₂ can collude.

Alice Bob Carol ✂ cut out Bob₂ Dave

Attack steps:
1. Bob sees HTLC from Alice: lock = H, forwards to Carol
2. Carol creates HTLC to Bob₂: lock = H (same!)
3. Bob₂ connects to Bob off-chain: "I see H from Carol, you see H from Alice — let's skip Carol!"
4. Bob creates a shortcut HTLC: Bob → Bob₂ directly with fee profit
5. Dave reveals R → Bob₂ claims from Bob directly → Carol gets nothing
6. Alice still pays Bob's full fee; Carol is cut out

Commitment Transactions — Revocation & Penalties

Channel state is tracked through commitment transactions. Old states are revoked by exchanging private keys — broadcasting a revoked state results in total loss of funds.

How Commitment Txs Work
Channel statePair of commitment txs (Alice's + Bob's)
Each state updateExchange new state, revoke old state
RevocationGive counterparty revocation privkey
Cheating penaltyCounterparty takes ALL funds
TimelockCSV: gives honest party time to react
Game-Theoretic Incentive

If Alice broadcasts state N-1 (old) instead of state N (latest), Bob uses Alice's revocation key for state N-1 to immediately claim all channel funds. The expected loss from cheating exceeds any possible gain.

Transaction Flow
OLD Commitment (State N-1)
Outputs:
 • Alice's balance (with CSV timelock)
 • Bob's balance (immediate)
 • Any active HTLCs
⚠️ Broadcasting this = CHEATING
↓ Alice broadcasts old state ↓
Justice Transaction
Bob detects old state on-chain.
Uses revocation key for state N-1.
Spends Alice's CSV output immediately.
Claims 100% of channel funds.
✅ Honest party wins everything

Animated: State Update Protocol

Watch how two channel parties exchange revocation keys to safely advance state.

Alice
→ new state →
← revocation ←
→ revocation →
Bob
Eltoo: The Alternative (No Penalties)

Eltoo (SIGHASH_ANYPREVOUT, BIP118) proposes replacing the revocation mechanism with update transactions that can override any previous state. No penalty needed — any later state can always spend any earlier state. Simpler channel factory construction, but requires new sighash type.

⏳ BIP118 pending activation Part of LN-Symmetry proposal