Glossary

OP_CHECKSIGADD

OP_CHECKSIGADD is a Tapscript opcode that enables efficient multi-signature verification by accumulating valid signature counts.

Key Takeaways

  • OP_CHECKSIGADD is a Tapscript opcode (introduced in BIP 342) that replaces OP_CHECKMULTISIG for building threshold signature schemes inside Taproot script-path spends.
  • Each public key is paired explicitly with its signature (or an empty placeholder), eliminating the sequential trial-and-skip matching that made legacy multisig incompatible with batch verification.
  • Activated at block 709,632 (November 2021) as part of the Taproot soft fork, OP_CHECKSIGADD enables larger, more efficient k-of-n threshold scripts using Schnorr signatures.

What Is OP_CHECKSIGADD?

OP_CHECKSIGADD (opcode 0xba) is a Bitcoin Script opcode available exclusively within Tapscript execution contexts. It verifies a single Schnorr signature against a public key and increments a running counter if the signature is valid. By chaining multiple OP_CHECKSIGADD calls together, script authors can construct k-of-n threshold signature schemes where k valid signatures out of n total public keys are required to spend.

The opcode was introduced in BIP 342 as a direct replacement for OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY, both of which are disabled in Tapscript and will cause immediate script failure if used. The redesign addresses fundamental problems with the legacy multisig opcode: an off-by-one bug requiring a dummy stack element, implicit signature-to-key matching that prevents batch verification, and imprecise sigops accounting.

How It Works

OP_CHECKSIGADD operates on three stack elements. It pops the public key (top), a counter value n (second), and a signature (third). The outcome depends on what signature is provided:

  • Empty signature: the opcode pushes n back onto the stack unchanged, and execution continues. This indicates the key is not a participant in this spend.
  • Valid non-empty signature: the opcode pushes n + 1 onto the stack, and execution continues. The counter advances by one.
  • Invalid non-empty signature: the entire script fails immediately. There is no "push false and continue" path as existed with legacy opcodes.

Functionally, OP_CHECKSIGADD is equivalent to the sequence OP_ROT OP_SWAP OP_CHECKSIG OP_ADD, but encoded as a single byte for efficiency.

Building a k-of-n Script

To construct a threshold script, the pattern starts with OP_CHECKSIG for the first key (which pushes 1 for valid or 0 for invalid), then chains OP_CHECKSIGADD for each subsequent key to accumulate the count. A final OP_NUMEQUAL or OP_NUMEQUALVERIFY checks whether the tally meets the threshold.

For a 2-of-3 multisig, the Tapscript looks like this:

<pubkey_A> OP_CHECKSIG
<pubkey_B> OP_CHECKSIGADD
<pubkey_C> OP_CHECKSIGADD
OP_2 OP_NUMEQUAL

The witness stack provides one element per key position, in reverse order. If keys A and B are the signers:

Witness: <> <sig_B> <sig_A>
         ↑       ↑       ↑
      key C   key B   key A
     (skipped) (valid) (valid)

Execution proceeds step by step:

  1. OP_CHECKSIG verifies sig_A against pubkey_A. Valid, so it pushes 1.
  2. OP_CHECKSIGADD pops pubkey_B, the counter (1), and sig_B. Valid, so it pushes 2.
  3. OP_CHECKSIGADD pops pubkey_C, the counter (2), and the empty element. Empty signature, so it pushes 2 unchanged.
  4. OP_NUMEQUAL checks that 2 equals 2. True: the script succeeds.

Comparison with Legacy OP_CHECKMULTISIG

The same 2-of-3 multisig using the legacy opcode:

Script:  OP_2 <pubkey_A> <pubkey_B> <pubkey_C> OP_3 OP_CHECKMULTISIG
Witness: OP_0 <sig_A> <sig_B>

The OP_0 at the front is a dummy element required by the original off-by-one bug in Satoshi's implementation. OP_CHECKMULTISIG consumes one more element than it should (m + n + 3 instead of m + n + 2). This dummy element was never validated, creating a transaction malleability vector until SegWit era rules (BIP 147) required it to be exactly an empty byte array.

AspectOP_CHECKMULTISIGOP_CHECKSIGADD
Signature typeECDSASchnorr (BIP 340)
Key-signature bindingImplicit (trial-and-skip)Explicit (position-bound)
Batch verificationIncompatibleCompatible
Dummy elementRequiredNot needed
Invalid signature behaviorPushes falseFails immediately
Sigops accounting20 per opcode (regardless of key count)50 weight units per non-empty check

Why It Matters

Batch Verification Compatibility

The most significant advantage of OP_CHECKSIGADD is enabling Schnorr batch verification. Because each signature is explicitly paired with its public key before verification begins, a node can collect all (message, public key, signature) triples across an entire block and verify them in a single batch operation. This is substantially faster than checking each signature individually.

Legacy OP_CHECKMULTISIG made this impossible because the verifier had to try signatures against keys sequentially at runtime to discover which key each signature corresponded to. The matching result was only known after verification, making it impossible to pre-assemble batches.

Cleaner Script Design

OP_CHECKSIGADD eliminates the dummy element waste, removes the ambiguity of implicit key matching, and makes script behavior more predictable. Every key position has a dedicated witness slot, which simplifies fee estimation and makes spending conditions transparent to static analysis tools.

Precise Resource Accounting

In legacy scripts, each OP_CHECKMULTISIG counted as 20 signature operations against the block's sigops limit, regardless of how many keys were actually involved. Tapscript replaces this with a per-input budget: each non-empty signature check costs 50 weight units, deducted from a budget of 50 plus the witness size in bytes. Empty signatures (skipped keys) cost nothing. This allows more efficient use of block space and enables larger threshold schemes.

Use Cases

Taproot Multisig Wallets

OP_CHECKSIGADD is the standard mechanism for k-of-n multisig inside script-path spends. A typical pattern places the most common signing quorum in the key path using MuSig2 or key aggregation, and reserves OP_CHECKSIGADD scripts in the Taptree as fallback spending conditions. For example, a 3-of-5 corporate treasury might use MuSig2 for routine 3-of-3 signing in the key path, with a 2-of-5 OP_CHECKSIGADD recovery script in the Taptree for when primary signers are unavailable.

Complex Spending Policies

Because OP_CHECKSIGADD scripts live inside a Taptree, different threshold combinations can coexist as separate leaves. A P2TR output can encode dozens of spending policies: a 2-of-3 for daily operations, a 3-of-5 for large withdrawals, and a time-locked 1-of-5 for disaster recovery, all in the same output without revealing unexercised conditions on-chain.

Lightning and Layer 2 Protocols

Layer 2 protocols built on Taproot, including simple Taproot channels and protocols like Spark, can use OP_CHECKSIGADD scripts as fallback enforcement mechanisms. While cooperative closes use efficient key-path spends, the script path can encode multi-party dispute resolution logic using threshold checks.

Relationship to MuSig2 and FROST

OP_CHECKSIGADD and interactive signing protocols like MuSig2 serve complementary roles in Taproot's signing ecosystem. MuSig2 aggregates multiple keys into a single public key, producing a single signature that is indistinguishable from a regular spend. This is more private and cheaper, but requires all signers to participate in an interactive protocol.

OP_CHECKSIGADD is better suited for scenarios where not all signers are expected to be online simultaneously, or where the exact set of signers varies. The tradeoff is that OP_CHECKSIGADD scripts reveal the number of keys and the threshold on-chain when spent (via the script path), while MuSig2 key-path spends reveal nothing about the signing policy.

For a deeper exploration of how these schemes compare, see the research articles on MuSig2 multisignatures and FROST threshold signatures.

Risks and Considerations

On-Chain Privacy Tradeoff

When an OP_CHECKSIGADD script is exercised through a script-path spend, the full script (including all public keys and the threshold) is revealed on-chain. This exposes the signing policy to chain analysis. Key-path spends using key aggregation are preferable for privacy whenever possible.

Witness Size for Large Thresholds

Every key position requires a witness element: either a 64-byte Schnorr signature or a 1-byte empty placeholder. For a 5-of-20 scheme, the witness includes 5 signatures and 15 empty elements, plus the full script with all 20 public keys (32 bytes each). While the precise per-signature accounting is more efficient than legacy multisig, very large threshold schemes can still consume significant block space.

Tapscript-Only Availability

OP_CHECKSIGADD is only valid within Tapscript execution (inside Taproot script-path spends). It cannot be used in legacy, SegWit v0 (P2WSH), or any non-Taproot context. Scripts must be wrapped in a P2TR output to use this opcode.

Fail-Fast Behavior

Unlike OP_CHECKMULTISIG, which pushes false for an invalid signature, OP_CHECKSIGADD causes immediate script failure if a non-empty invalid signature is provided. This is a deliberate security design: it prevents scripts from accidentally accepting bad signatures in alternative code paths. However, wallet implementations must ensure they only provide correctly constructed Schnorr signatures or empty placeholders.

This glossary entry is for informational purposes only and does not constitute financial or investment advice. Always do your own research before using any protocol or technology.