Definition
OP_CHECKMULTISIG (opcode 0xae) implements classic m-of-n multisignature validation in legacy Bitcoin Script. It reads a public-key count n and n public keys from the stack, then a signature count m and m signatures, and returns true only if every supplied signature matches a distinct key, evaluated in order. This single opcode powered the original Pay-to-Multisig (P2MS) outputs and the vast majority of P2SH and P2WSH multisig wallets that secured exchange cold storage, escrow arrangements, and personal vaults for a decade before Taproot.
How the matching actually works
The opcode enforces order, not search: it walks the signature list and the key list together, and each signature must verify against a key that appears later or at the same position in the key list than the previous match. Signatures supplied out of key order therefore fail even when each one is individually valid — a detail that has bitten many hand-rolled wallet implementations. Limits apply too: legacy consensus caps the key count at 20, and each key in the script counts against block-level signature-operation limits, which is one reason large multisig sets were expensive to deploy.
The famous off-by-one bug
The original implementation pops one more element off the stack than it needs. To keep scripts from failing, spenders must prepend a throwaway "dummy" element beneath the signature list. Because that extra value was originally unconstrained, any byte string would do — which made it a transaction-malleability vector: a relay node could swap the dummy for a different value and change the transaction ID without invalidating it. BIP 147's NULLDUMMY rule, activated alongside SegWit, fixed this by requiring the dummy to be an empty byte array (OP_0); anything else now renders the script invalid. The bug itself could never be removed, because doing so would change the meaning of every existing multisig output — a clean illustration of why Bitcoin treats consensus code as effectively immutable and layers corrections on top instead.
Why Tapscript retired it
OP_CHECKMULTISIG does not bind specific signatures to specific keys until runtime, forcing validators into a matching loop and — more importantly — defeating Schnorr batch verification, where many signatures are checked together in one aggregated operation. Tapscript (BIP 342) therefore disables the opcode entirely and replaces it with the batch-friendly OP_CHECKSIGADD, which increments a counter for each valid signature and lets the script compare the total against the threshold. The result is the same m-of-n policy expressed in a form Schnorr verification can consume efficiently.
What this means for a self-custody operator
There is also a fee dimension worth knowing. Under legacy rules, each OP_CHECKMULTISIG in a bare or P2SH script counts as up to twenty signature operations against the block's sigop limit, regardless of how many keys the script actually uses — an accounting quirk that made multisig disproportionately "expensive" to the network even when the witness bytes were modest. Miners assembling block templates must respect that budget, so the opcode's true cost was always higher than its byte count suggested.
If you run multisig cold storage today, the opcode your coins rely on depends on the address era: legacy and SegWit v0 vaults still execute OP_CHECKMULTISIG on every spend, while Taproot-era wallets use OP_CHECKSIGADD inside script leaves or avoid on-chain multisig entirely through key aggregation. Neither is wrong — the old opcode remains fully secure under NULLDUMMY — but the new constructions are cheaper in fees and reveal less about your setup. Understanding the difference explains why post-Taproot multisig looks different in a block explorer and why sweep transactions from old vaults cost more virtual bytes. The opcode pairs naturally with the single-signature primitive covered in OP_CHECKSIG, and its heavy signature-operation accounting is part of why the modern sigop budget exists in Tapscript at all.
In Simple Terms
OP_CHECKMULTISIG (opcode 0xae) implements classic m-of-n multisignature validation in legacy Bitcoin Script. It reads a public-key count n and n public keys from the stack,…
