TeachMeBitcoin

The redeem script (the actual spending conditions):

From TeachMeBitcoin, the free encyclopedia Reading time: 3 min

2. Fully Annotated 2-of-3 Multisig Execution

A 2-of-3 multisig requires any 2 of 3 designated parties to sign before coins can be spent. This is the standard setup for organizational wallets, escrow, and shared custody.

P2SH-Wrapped 2-of-3 Multisig Structure

Modern 2-of-3 multisig uses P2SH to hide the public keys until spend time:

# The redeem script (the actual spending conditions):
redeem_script = (
    "OP_2 "
    "<pubkey1_33bytes> "
    "<pubkey2_33bytes> "
    "<pubkey3_33bytes> "
    "OP_3 "
    "OP_CHECKMULTISIG"
)

# Hex representation:
# 52 = OP_2
# 21 <33 bytes> = push pubkey1
# 21 <33 bytes> = push pubkey2
# 21 <33 bytes> = push pubkey3
# 53 = OP_3
# ae = OP_CHECKMULTISIG
# Total redeem script: 105 bytes

# The P2SH locking script (what goes on-chain):
p2sh_script = "OP_HASH160 " + HASH160(redeem_script) + " OP_EQUAL"
# Hex: a9 14 <20-byte-hash> 87

The Spending Transaction

ScriptSig for 2-of-3 P2SH multisig (sigs from key1 and key3):

00            → OP_0 (dummy item for CHECKMULTISIG bug)
48            → Push 72 bytes
<sig1><01>    → Signature from key1 + SIGHASH_ALL byte (71 bytes + 1)
48            → Push 72 bytes  
<sig3><01>    → Signature from key3 + SIGHASH_ALL byte
69            → Push 105 bytes (the redeem script)
<redeem_script> → The full 105-byte redeem script

Full Execution Trace

Starting state:
Main stack: []

=== PHASE 1: Execute scriptSig ===

Step 1: OP_0
  Stack: [0x00]  ← the dummy item (CHECKMULTISIG bug workaround)

Step 2: Push <sig1>
  Stack: [0x00, <sig1>]

Step 3: Push <sig3>
  Stack: [0x00, <sig1>, <sig3>]

Step 4: Push <redeem_script>
  Stack: [0x00, <sig1>, <sig3>, <redeem_script>]

=== PHASE 2: Execute scriptPubKey (P2SH outer script) ===

Step 5: OP_HASH160
  Operation: Hash the top item (the redeem script)
  Before: [0x00, <sig1>, <sig3>, <redeem_script>]
  After:  [0x00, <sig1>, <sig3>, HASH160(<redeem_script>)]

Step 6: Push <scriptHash> (the expected hash from scriptPubKey)
  Before: [0x00, <sig1>, <sig3>, HASH160(<redeem_script>)]
  After:  [0x00, <sig1>, <sig3>, HASH160(<redeem_script>), <expectedHash>]

Step 7: OP_EQUAL
  Operation: Compare top two items
  Before: [0x00, <sig1>, <sig3>, HASH160(<redeem_script>), <expectedHash>]
  If equal: Stack: [0x00, <sig1>, <sig3>, 1]

  P2SH check passes — the redeem script is the one committed to.

=== PHASE 3: Execute redeem script ===
(P2SH special handling: deserialize and run the redeem script)

Stack entering Phase 3: [0x00, <sig1>, <sig3>]

### Step 8: OP_2
**Operation:** Push integer 2 (required number of sigs)
**Stack:** `[0x00, <sig1>, <sig3>, 2]`

Step 9: Push <pubkey1>
  Stack: [0x00, <sig1>, <sig3>, 2, <pk1>]

Step 10: Push <pubkey2>
  Stack: [0x00, <sig1>, <sig3>, 2, <pk1>, <pk2>]

Step 11: Push <pubkey3>
  Stack: [0x00, <sig1>, <sig3>, 2, <pk1>, <pk2>, <pk3>]

### Step 12: OP_3
**Operation:** Push integer 3 (total number of keys)
**Stack:** `[0x00, <sig1>, <sig3>, 2, <pk1>, <pk2>, <pk3>, 3]`

Step 13: OP_CHECKMULTISIG
  Operation: Pop M=2, pop N=3 keys, pop N keys, pop M sigs, pop dummy

  Internal process:
  1. Pop N=3: read pk3, pk2, pk1 from stack
  2. Pop M=2: try to match 2 signatures
  3. Try sig3 against pk1: FAIL
  4. Try sig3 against pk2: FAIL
  5. Try sig3 against pk3: SUCCESS ✓
  6. Try sig1 against pk1: SUCCESS ✓
  7. Both sigs matched — push 1
  8. Pop dummy OP_0 (the bug — it consumes one extra item)

  Final stack: [1]

=== FINAL CHECK ===
Stack top: 1 → TRUE → Transaction VALID

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.

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