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