TeachMeBitcoin

Recipient (Bob) creates the payment secret:

From TeachMeBitcoin, the free encyclopedia Reading time: 4 min

13. HTLC Scripts: Combining Hash and Timelocks

What Is an HTLC?

A Hash Time-Locked Contract (HTLC) is the core building block of the Lightning Network and cross-chain atomic swaps. It combines two cryptographic primitives:

  1. Hash Lock: Payment is only possible if the recipient can reveal a secret preimage such that HASH(preimage) == H. This enables trustless payment routing.

  2. Time Lock: If the secret is not revealed within a timeout period, the sender can reclaim the funds.

The combination of these two elements enables payments to be routed across untrusted intermediaries without requiring trust — the intermediary either knows the preimage (and gets paid) or doesn't (and the funds time out safely back to the sender).

The Hash Lock Mechanism

import hashlib
import secrets

# Recipient (Bob) creates the payment secret:
preimage = secrets.token_bytes(32)  # 32 random bytes
payment_hash = hashlib.sha256(preimage).digest()  # H = SHA256(preimage)

print(f"Preimage: {preimage.hex()}")
print(f"Payment Hash: {payment_hash.hex()}")

# Bob shares payment_hash (H) with Alice (the payer).
# Alice creates an HTLC locked to H.
# Bob claims the HTLC by revealing preimage.
# Alice (or intermediate nodes) learn preimage when Bob reveals it.

On-Chain HTLC Script (P2WSH)

# Offered HTLC: Alice → Bob (Alice offering, Bob receiving)
# Bob can claim by revealing preimage within timeout
# Alice can reclaim after CLTV timeout

witnessScript:
  OP_DUP OP_HASH160 <RevocationPubKeyHash> OP_EQUAL
  OP_IF
    OP_CHECKSIG
  OP_ELSE
    <RemotePubKey> OP_SWAP OP_SIZE 32 OP_EQUAL
    OP_IF
      OP_HASH160 <PaymentHashRIPEMD160> OP_EQUALVERIFY
      2 OP_SWAP <LocalPubKey> 2 OP_CHECKMULTISIG
    OP_ELSE
      OP_DROP <CLTVExpiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
      OP_CHECKSIG
    OP_ENDIF
  OP_ENDIF

# Path 1 (Revocation): Bob uses revocation key to punish Alice for old state
# Path 2 (Success): Bob reveals 32-byte preimage → receives payment
# Path 3 (Timeout): Alice reclaims after CLTV expiry block

Received HTLC Script

# Received HTLC: Alice receiving payment from remote
# Similar structure but the roles are reversed

witnessScript:
  OP_DUP OP_HASH160 <RevocationPubKeyHash> OP_EQUAL
  OP_IF
    OP_CHECKSIG
  OP_ELSE
    <RemotePubKey> OP_SWAP OP_SIZE 32 OP_EQUAL
    OP_NOTIF
      OP_DROP <CLTVExpiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
      OP_CHECKSIG
    OP_ELSE
      OP_HASH160 <PaymentHashRIPEMD160> OP_EQUALVERIFY
      2 OP_SWAP <LocalPubKey> 2 OP_CHECKMULTISIG
    OP_ENDIF
  OP_ENDIF

The HTLC-Timeout Transaction

When an offered HTLC times out (Bob didn't reveal the preimage), Alice broadcasts an HTLC-Timeout second-level transaction:

# HTLC-Timeout TX:
# Input: Offered HTLC output (from commitment TX)
# Output: to_local-style output with CSV delay

# Input witness:
  0                   # OP_CHECKMULTISIG dummy
  <AliceSignature>
  <BobSignature>
  ""                  # Empty preimage (timeout path)
  0                   # OP_ELSE branch
  <htlc_witnessScript>

# nLockTime: set to CLTVExpiry (satisfies the CLTV in the HTLC script)
# Input nSequence: 0 (allows nLockTime to be enforced)

# Output script (to_local with CSV):
  OP_IF
    <RevocationPubKey> OP_CHECKSIG
  OP_ELSE
    <csv_delay> OP_CSV OP_DROP
    <AliceDelayedPubKey> OP_CHECKSIG
  OP_ENDIF

Atomic Swaps Using HTLCs

HTLCs enable trustless cross-chain swaps between Bitcoin and other cryptocurrencies:

# Cross-chain atomic swap: Alice wants to trade BTC for LTC with Bob
# Both chains must support hash locks and timelocks

# Step 1: Bob generates preimage and hash
preimage = secrets.token_bytes(32)
H = hashlib.sha256(preimage).digest()

# Step 2: Alice creates Bitcoin HTLC (funds locked to H, 48-hour CLTV)
bitcoin_htlc = f"""
  OP_IF
    OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 {H.hex()} OP_EQUALVERIFY
    OP_DUP OP_HASH160 {bob_btc_hash} OP_EQUALVERIFY OP_CHECKSIG
  OP_ELSE
    {bitcoin_cltv_expiry} OP_CLTV OP_DROP
    OP_DUP OP_HASH160 {alice_btc_hash} OP_EQUALVERIFY OP_CHECKSIG
  OP_ENDIF
"""

# Step 3: Bob creates Litecoin HTLC (same H, 24-hour CLTV — shorter than Bitcoin!)
litecoin_htlc = f"""
  OP_IF
    OP_SIZE 32 OP_EQUALVERIFY OP_SHA256 {H.hex()} OP_EQUALVERIFY
    OP_DUP OP_HASH160 {alice_ltc_hash} OP_EQUALVERIFY OP_CHECKSIG
  OP_ELSE
    {litecoin_cltv_expiry} OP_CLTV OP_DROP
    OP_DUP OP_HASH160 {bob_ltc_hash} OP_EQUALVERIFY OP_CHECKSIG
  OP_ENDIF
"""

# Step 4: Alice claims LTC by revealing preimage (on Litecoin blockchain)
# Step 5: Bob learns preimage from Alice's Litecoin claim
# Step 6: Bob claims BTC using the same preimage (on Bitcoin blockchain)

HTLC Security Properties

| Property | Guarantee | |

☕ Help support TeachMeBitcoin

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:

Ethereum: 0x578417C51783663D8A6A811B3544E1f779D39A85
Bitcoin: bc1q77k9e95rn669kpzyjr8ke9w95zhk7pa5s63qzz
Solana: 4ycT2ayqeMucixj3wS8Ay8Tq9NRDYRPKYbj3UGESyQ4J
Address copied to clipboard!