TeachMeBitcoin

OP_IF vs OP_NOTIF - When to Use Which

From TeachMeBitcoin, the free encyclopedia Reading time: 3 min

7. OP_IF vs OP_NOTIF — When to Use Which

Overview

Choosing between OP_IF and OP_NOTIF is partly a matter of script design philosophy, partly readability, and partly convention. Both are semantically equivalent (one is the boolean inverse of the other), but the choice affects how spending witnesses are structured and how script authors communicate intent.

Symmetry and Equivalence

; These two scripts are logically equivalent:

; Using OP_IF:
<selector>
OP_IF
  <path A>
OP_ELSE
  <path B>
OP_ENDIF

; Using OP_NOTIF:
<selector>
OP_NOTIF
  <path B>   ; branches are swapped!
OP_ELSE
  <path A>
OP_ENDIF

The spending witness for the first (OP_IF) version:

The spending witness for the second (OP_NOTIF) version:

So: Path B is activated by OP_0, Path A by OP_1 — same witness structure. Only the branch ordering in the script changes.

Convention: OP_IF for the Happy Path

By convention in Bitcoin script design, OP_IF is used when the "normal" or "happy path" is the primary case (activated by OP_1). OP_NOTIF is used when you want to express "if this condition is NOT met, do something special."

; Convention: OP_IF for happy path (payment path in HTLC)
OP_IF
  ; Payment path: preimage provided
  OP_SHA256 <hash> OP_EQUALVERIFY
  <recipient_pubkey> OP_CHECKSIG
OP_ELSE
  ; Timeout path: fallback
  <timeout> OP_CHECKLOCKTIMEVERIFY OP_DROP
  <sender_pubkey> OP_CHECKSIG
OP_ENDIF

Convention: OP_NOTIF for Absence-Based Logic

OP_NOTIF excels when the condition being tested is naturally a "guard" — you want to take action when something is absent or invalid.

; Check if a value is provided; if not, use default
OP_DUP OP_0 OP_EQUAL   ; is the top value zero/empty?
OP_NOTIF
  ; Value is present — process it
  OP_SHA256
OP_ELSE
  ; Value is absent — use default hash
  <default_hash>
OP_ENDIF

Performance Considerations

In Bitcoin, script execution cost is measured in script size (vbytes) and opcode count. OP_IF and OP_NOTIF both consume exactly one byte and one opcode unit. There is no performance difference between them. The choice is purely semantic and organizational.

Readability Guidelines

Scenario Recommended Opcode
Primary spending condition tested first OP_IF
Timeout / fallback tested first OP_IF with OP_ELSE for fallback
Condition is naturally a negation OP_NOTIF
Mimicking "unless" semantics OP_NOTIF
Standard HTLC scripts OP_IF (BOLT spec convention)

Real Code Comparison

; OP_IF approach — Lightning HTLC offered HTLC:
OP_DUP OP_HASH160 <RIPEMD160(remote_pubkey)> OP_EQUALVERIFY OP_CHECKSIGVERIFY
OP_SIZE 32 OP_EQUAL
OP_IF
  OP_SHA256 <payment_hash> OP_EQUALVERIFY
  OP_2 <local_pubkey> <remote_pubkey> OP_2 OP_CHECKMULTISIG
OP_ELSE
  <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP OP_CHECKSIG
OP_ENDIF

; OP_NOTIF approach — same logic, rearranged:
OP_DUP OP_HASH160 <RIPEMD160(remote_pubkey)> OP_EQUALVERIFY OP_CHECKSIGVERIFY
OP_SIZE 32 OP_EQUAL
OP_NOTIF
  <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP OP_CHECKSIG
OP_ELSE
  OP_SHA256 <payment_hash> OP_EQUALVERIFY
  OP_2 <local_pubkey> <remote_pubkey> OP_2 OP_CHECKMULTISIG
OP_ENDIF

The Lightning Network BOLT specification standardizes the OP_IF approach, so consistency with reference implementations favors OP_IF in HTLC contexts.

☕ 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!