HTLC execution — Bob claiming with preimage:
3. Fully Annotated Lightning HTLC Script
A Hash Time Locked Contract (HTLC) is the core primitive of Lightning Network routing. It creates a conditional payment: "You can claim these funds if you reveal the preimage of this hash — but only until this block height."
The Offered HTLC Script
When Alice routes a payment through Bob to Carol, Alice creates an HTLC output in her commitment transaction with Bob:
Offered HTLC scriptPubKey (Alice → Bob channel, routing to Carol):
OP_DUP OP_HASH160 <revocation_pubkey_hash> OP_EQUAL
OP_IF
OP_CHECKSIG
OP_ELSE
<remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
OP_IF
OP_HASH160 <payment_hash160> OP_EQUALVERIFY
OP_2 <local_htlcpubkey> <remote_htlcpubkey> OP_2 OP_CHECKMULTISIG
OP_ELSE
OP_DROP <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
OP_CHECKSIG
OP_ENDIF
OP_ENDIF
Three Spending Paths Explained
Path 1: Bob claims with payment preimage (success case)
Witness: [0, <bob_sig>, <alice_sig>, <preimage>, ""]
- Bob knows the preimage (Carol revealed it to him)
- Both Alice and Bob sign
- OP_SIZE 32 ensures preimage is exactly 32 bytes
- OP_HASH160 verifies preimage matches payment hash
Path 2: Alice revokes an old state (penalty case)
Witness: [<alice_revocation_sig>]
- Alice uses revocation key if Bob broadcasts an old commitment
- First branch: direct OP_CHECKSIG with revocation key
Path 3: HTLC timeout (payment failed)
Witness: [0, <alice_sig>, ""]
- After CLTV expiry, Alice can reclaim the funds
- Proves payment route failed
Simplified HTLC Execution (Success Path)
# HTLC execution — Bob claiming with preimage:
initial_stack = ["", "<preimage>", "<alice_sig>", "<bob_sig>", "0"]
# Witness items pushed in reverse order
# Step 1: OP_DUP OP_HASH160 <revocation_pubkey_hash> OP_EQUAL
# Top of stack is "0" — not equal to revocation hash
# OP_IF evaluates FALSE → takes OP_ELSE branch
# Step 2: Enter ELSE branch
# <remote_htlcpubkey> pushed
# OP_SWAP: swaps top two items
# OP_SIZE: pushes byte length of preimage (should be 32)
# OP_EQUAL: checks if size == 32 → TRUE if preimage is 32 bytes
# Step 3: OP_IF (inner) — preimage size is 32, so TRUE
# OP_HASH160 <payment_hash160> OP_EQUALVERIFY
# Verifies preimage hashes to expected payment hash
# Step 4: OP_2 <local_htlcpubkey> <remote_htlcpubkey> OP_2 OP_CHECKMULTISIG
# Requires both alice_sig and bob_sig
# SUCCESS if both valid
Preimage Size Check — Why 32 Bytes
// The size check is critical for security:
<remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
// Without this check:
// Mallory could provide a 1-byte "preimage" that happens to produce
// the correct HASH160 (birthday attack easier with shorter inputs)
// The 32-byte requirement forces use of full SHA256 preimage space
Technical Insight
This topic covers essential mechanics for Chapter 12. Understanding these details is key to mastering advanced Bitcoin script constructions like Taproot and specialized covenants.
TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation: