TYPE 0x0702 · COMPOUND FAMILY

HTLC

Hash Time Locked Contract — hash preimage verification, relative timelock, and signature check combined in a single block. Collapses a hash + CSV + SIG three-block pattern, saving 16 bytes on wire.

Compound Non-Invertible
HTLC HASH CHECK + CSV CHECK + SIG VERIFY 3 BLOCKS → 1 SAVES 16B All three checks must pass sequentially
FieldData TypeSizeSideDescription
hash HASH256 32 B Conditions SHA-256 hash that the receiver-path preimage must match. F24: the descriptor surface accepts either form — htlc(@r, @s, <preimage_hex>, csv) auto-SHA256s the input, while htlc(@r, @s, h:<HASH256_hex>, csv) stores the supplied 32-byte hash verbatim. Both produce identical conditions; the h: form is what formatladder emits so that parse → format → parse round-trips at the conditions-root level.
csv NUMERIC 1-4 B Conditions Relative timelock in blocks (BIP-68 sequence value) for the refund path.
scheme SCHEME 1 B Conditions Signature scheme byte routed into VerifySigWithScheme on either path.
receiver_pubkey PUBKEY 32-33 B Witness Receiver pubkey (witness PUBKEY index 0). Used by the receiver/early path.
sender_pubkey PUBKEY 32-33 B Witness Sender pubkey (witness PUBKEY index 1). Used by the sender/refund path. Both keys are revealed even if only one is consumed by the sig — the rung leaf reconstruction at MLSC-proof level needs both.
signature SIGNATURE var Witness Single signature; verified against receiver_pubkey on path 0 or sender_pubkey on path 1.
preimage PREIMAGE var Witness On path 0 (receiver): non-empty preimage whose SHA-256 must equal hash. On path 1 (refund): must be empty — closes the embedding channel.
path NUMERIC 1 B Witness Path indicator: 0 = receiver (hashlock claim, no CSV), 1 = sender (CSV refund, no preimage). Any other value → ERROR.

PubkeyCountForBlock = 2; both pubkeys revealed in the witness for leaf reconstruction (closes audit finding E-002 by ensuring both keys are consumed across the two paths). The implicit witness layout has a strict 5-field shape; the evaluator rejects anything that does not match exactly.

Conditions side (committed in the rung leaf):

0x0702 0 3 HASH256 · 32B NUMERIC · 3B SCHEME · 1B ≈ 40 bytes

Witness side:

0x0702 0 5 PUBKEY · 35B (rcv) PUBKEY · 35B (snd) SIGNATURE · 66B PREIMAGE · var NUMERIC · 1B (path) ≈ 175 + len bytes
Total (conditions + witness) ≈ 215 + len bytes

Compared to separate hash + CSV + SIG blocks: 233 bytes → 217 bytes (saves 16B / 6.9%)

Compared to equivalent Tapscript (2-leaf P2TR, claim path): 265 bytes → 217 bytes (saves 48B / 18.1%)

1. Strict shape check: the merged conditions+witness block must have exactly 3 + 5 = 8 fields with the exact type sequence HASH256, NUMERIC, SCHEME, PUBKEY, PUBKEY, SIGNATURE, PREIMAGE, NUMERIC. Anything else → ERROR
2. Verify the conditions HASH256 is exactly 32 B. ReadNumeric the path indicator (witness NUMERIC); undecodable → ERROR
3. path == 0 (receiver/early): PREIMAGE must be non-empty (else UNSATISFIED). Compute SHA256(PREIMAGE); mismatch with conditions HASH256 → UNSATISFIED. Then dispatch VerifySigWithScheme(receiver_pubkey, sig, scheme, ...); the sig result is the block result. CSV is not enforced on this path.
4. path == 1 (sender/refund): PREIMAGE must be empty (anti-data-embedding); else → ERROR. ReadNumeric the conditions CSV; undecodable → ERROR. SEQUENCE_LOCKTIME_DISABLE_FLAG set → ERROR (defeats the refund timer). Range guard: out of uint32 → UNSATISFIED. CheckSequence(uint32_t(csv)) fails → UNSATISFIED. Then dispatch VerifySigWithScheme(sender_pubkey, sig, scheme, ...); the sig result is the block result.
5. Any other path value → ERROR. On UNSATISFIED, ctx.error_message_out (if non-null) is populated with the specific check that fired ("HTLC: path=0 preimage hash mismatch", etc.) so mempool reject reasons carry the diagnostic.
ConditionResult
Field count or type sequence does not match the strict 8-field shapeERROR
HASH256 not exactly 32 B; or path NUMERIC undecodable; or path not in {0,1}ERROR
path == 0 (receiver): PREIMAGE emptyUNSATISFIED
path == 0: SHA256(preimage) ≠ hashUNSATISFIED
path == 1 (refund): PREIMAGE non-empty (anti-embedding)ERROR
path == 1: SEQUENCE_LOCKTIME_DISABLE_FLAG set, or CSV undecodableERROR
path == 1: CSV out of uint32 range, or CheckSequence failsUNSATISFIED
SIG verification fails on the selected pubkeyUNSATISFIED
Selected path's checks all passSATISFIED
Conditions (committed in the rung leaf)
{
  "type": "HTLC",
  "inverted": false,
  "fields": [
    { "type": "HASH256", "hex": "e3b0c44298fc1c... preimage hash 32 bytes" },
    { "type": "NUMERIC", "value": 144 },
    { "type": "SCHEME", "hex": "01" }
  ]
}
Witness — receiver path (path = 0, hashlock claim)
{
  "type": "HTLC",
  "fields": [
    { "type": "PUBKEY",    "hex": "02aabb... receiver pubkey" },
    { "type": "PUBKEY",    "hex": "02ccdd... sender pubkey (still revealed)" },
    { "type": "SIGNATURE", "hex": "... receiver Schnorr sig ..." },
    { "type": "PREIMAGE",  "hex": "deadbeef... preimage hashing to the conditions HASH256" },
    { "type": "NUMERIC",   "value": 0 }
  ]
}
Witness — refund path (path = 1, CSV must be elapsed)
{
  "type": "HTLC",
  "fields": [
    { "type": "PUBKEY",    "hex": "02aabb... receiver pubkey (still revealed)" },
    { "type": "PUBKEY",    "hex": "02ccdd... sender pubkey" },
    { "type": "SIGNATURE", "hex": "... sender Schnorr sig ..." },
    { "type": "PREIMAGE",  "hex": "" },
    { "type": "NUMERIC",   "value": 1 }
  ]
}
Lightning Network Payment Channels
HTLCs are the core payment routing primitive. Each pending payment in a channel commitment has a claim path (preimage + sig) and timeout path (CSV + sig). The compound HTLC block handles the claim path in a single evaluation dispatch, reducing per-HTLC overhead.
Cross-Chain Atomic Swaps
Alice locks BTC with an HTLC where Bob can claim with a preimage. Bob locks altcoin with the same hash. Alice claims the altcoin (revealing preimage), Bob uses the revealed preimage to claim BTC.
Conditional Escrow
Payment released when a secret is revealed (preimage), but only within a time window. After the CSV delay, the sender can reclaim funds via a separate timeout rung.