Glossary

OP_CHECKSIG

The Bitcoin Script opcode that verifies a digital signature against a public key, the most fundamental operation in Bitcoin transactions.

Key Takeaways

  • OP_CHECKSIG (opcode 0xac) is the Bitcoin Script instruction that verifies a digital signature against a public key: it is the core mechanism that proves ownership of bitcoin and authorizes spending.
  • In legacy and SegWit transactions, OP_CHECKSIG verifies ECDSA signatures on the secp256k1 curve. In Taproot script-path spends, it verifies Schnorr signatures instead, enabling batch verification and simpler multisig constructions.
  • Sighash flags appended to each signature control which parts of the transaction OP_CHECKSIG commits to, enabling advanced spending conditions like anyone-can-pay fundraising and single-output binding.

What Is OP_CHECKSIG?

OP_CHECKSIG is the Bitcoin Script opcode responsible for verifying that a digital signature is valid for a given public key and transaction context. Every time someone spends bitcoin, the network must confirm that the spender controls the private key corresponding to the locking script. OP_CHECKSIG performs this check by popping a public key and a signature from the stack, computing a hash of the transaction data, and running cryptographic verification against that hash.

Without OP_CHECKSIG, Bitcoin would have no way to enforce ownership. It is present (either explicitly or implicitly) in virtually every standard transaction type: P2PKH, P2WPKH, and Taproot script-path spends all rely on it. Even SegWit v0 P2WPKH inputs use an implicit script containing OP_CHECKSIG under the hood.

How It Works

OP_CHECKSIG operates differently depending on the transaction type: legacy, SegWit v0, or Tapscript. The core concept remains the same: hash the relevant parts of the transaction, then verify the signature against that hash using the provided public key.

Legacy Transaction Verification

In legacy (pre-SegWit) transactions, OP_CHECKSIG follows a multi-step process that dates back to the original Bitcoin implementation:

  1. Pop the public key and signature from the stack
  2. Extract the sighash flag from the last byte of the signature
  3. Create a "subscript" (scriptCode) from the most recent OP_CODESEPARATOR to the end of the script, or the entire script if no OP_CODESEPARATOR exists
  4. Remove any occurrences of the signature from the subscript (the FindAndDelete step)
  5. Remove all OP_CODESEPARATOR opcodes from the subscript
  6. Create a modified copy of the transaction: zero out all input scripts, then set the current input's script to the subscript
  7. Apply the sighash flag to further modify which inputs and outputs are included
  8. Serialize the modified transaction with the four-byte hash type appended
  9. Double SHA-256 hash the serialized data to produce a 32-byte digest
  10. Verify the ECDSA signature against this digest using the secp256k1 curve
  11. Push TRUE (1) or FALSE (0) onto the stack

This process is computationally straightforward for a single verification but becomes important at scale: every node on the network must execute OP_CHECKSIG for every input of every transaction it validates.

SegWit v0 Verification

Segregated Witness (BIP 143) introduced a new transaction digest algorithm that fixed quadratic hashing issues and eliminated the FindAndDelete step for witness scripts. The sighash computation precommits to the value being spent, preventing offline signing attacks. P2WPKH inputs use an implicit scriptCode equivalent to the P2PKH pattern:

OP_DUP OP_HASH160 <20-byte-pubkey-hash> OP_EQUALVERIFY OP_CHECKSIG

This script is not written on-chain: consensus rules construct it internally when validating P2WPKH outputs. The signature and public key are provided in the witness data, separate from the scriptSig.

Tapscript Verification (BIP 342)

Taproot introduced the most significant change to OP_CHECKSIG since Bitcoin's creation. Within Tapscript (the scripting rules for Taproot script-path spends), OP_CHECKSIG now verifies Schnorr signatures per BIP 340 instead of ECDSA. Key differences include:

  • Schnorr signatures are exactly 64 bytes (no DER encoding), saving space and simplifying parsing
  • The sighash message includes the tapleaf_hash, committing to the specific script being executed
  • FindAndDelete is eliminated entirely: the script commitment uses the tapleaf_hash rather than scriptCode
  • A new default sighash type (0x00) behaves like SIGHASH_ALL but omits the sighash byte from the signature, saving 1 byte
  • Batch verification is possible: multiple Schnorr signatures can be verified together faster than individually

For key-path spends (the most common Taproot spend), no OP_CHECKSIG executes at all: the Taproot validation rules verify the Schnorr signature directly against the tweaked output key. OP_CHECKSIG only runs in script-path spends where the revealed script contains it. For a deeper look at how Taproot changed Bitcoin's signature model, see the Taproot and Schnorr signatures explainer.

Sighash Flags

The sighash flag appended to each signature tells OP_CHECKSIG which parts of the transaction to include in the digest. This determines what the signer is committing to and what remains modifiable after signing.

FlagValueInputs SignedOutputs Signed
SIGHASH_ALL0x01AllAll
SIGHASH_NONE0x02AllNone
SIGHASH_SINGLE0x03AllSame-index output only
SIGHASH_ALL | ANYONECANPAY0x81Current input onlyAll
SIGHASH_NONE | ANYONECANPAY0x82Current input onlyNone
SIGHASH_SINGLE | ANYONECANPAY0x83Current input onlySame-index output only

SIGHASH_ALL is the default used by virtually all consumer wallets. The ANYONECANPAY modifier (0x80) allows additional inputs to be added after signing, enabling patterns like crowdfunding transactions where multiple parties contribute inputs toward fixed outputs.

Common Script Patterns

OP_CHECKSIG appears in several standard Bitcoin Script patterns. Understanding these shows how the opcode fits into real transaction validation.

P2PKH (Pay-to-Public-Key-Hash)

The most widely used legacy transaction type. P2PKH first verifies the public key hashes to the expected value, then checks the signature:

// Locking script (scriptPubKey)
OP_DUP OP_HASH160 <pubkey-hash> OP_EQUALVERIFY OP_CHECKSIG

// Unlocking script (scriptSig)
<signature> <pubkey>

P2PK (Pay-to-Public-Key)

The simplest pattern, used in early Bitcoin transactions including the genesis block. The public key is embedded directly in the locking script:

// Locking script (scriptPubKey)
<pubkey> OP_CHECKSIG

// Unlocking script (scriptSig)
<signature>

P2PK is considered obsolete because it exposes the public key on-chain before spending, offering less privacy than hash-based outputs.

OP_CHECKSIGADD in Tapscript

BIP 342 introduced OP_CHECKSIGADD (opcode 0xba) as a replacement for OP_CHECKMULTISIG in Tapscript. OP_CHECKMULTISIG was disabled in Tapscript because its trial-and-skip approach to matching signatures with keys is incompatible with Schnorr batch verification.

OP_CHECKSIGADD pops a public key, a counter, and a signature. If the signature is valid, it increments the counter. A 2-of-3 multisig in Tapscript looks like:

<pubkey1> OP_CHECKSIG
<pubkey2> OP_CHECKSIGADD
<pubkey3> OP_CHECKSIGADD
2 OP_NUMEQUAL

Each valid signature increments the counter by one. The final OP_NUMEQUAL checks that exactly two signatures were valid. This pattern is compatible with batch verification and makes multisig spending policies straightforward in Taproot. For more on how Bitcoin handles multi-party signing, see the research on MuSig2 multisignatures.

Sigops Budget and Script Cost

Each OP_CHECKSIG execution consumes "sigops" (signature operations), which Bitcoin uses to limit the computational cost of block validation.

  • Legacy transactions: each OP_CHECKSIG counts as 1 sigop, multiplied by 4 for block weight. The block limit is 80,000 sigop weight units.
  • SegWit v0: witness sigops are counted at face value (1x), not multiplied by 4.
  • Tapscript: replaces the block-wide sigops limit with a per-input budget. Each input gets a budget of 50 plus the total witness size in bytes. Each signature verification costs 50 from this budget. The script fails if the budget drops below zero.

The Tapscript budgeting model is more flexible: larger witnesses (which pay higher fees due to weight) earn a larger sigops budget, aligning economic incentives with validation cost.

Use Cases

Standard Payments

Every standard Bitcoin payment uses OP_CHECKSIG. When you send bitcoin from a wallet, the transaction includes a signature proving you control the private key for the UTXO being spent. The receiving node executes OP_CHECKSIG to verify this proof before accepting the transaction.

Multisignature Wallets

Multisig wallets use multiple OP_CHECKSIG operations (or OP_CHECKSIGADD in Tapscript) to require signatures from more than one key. This is the foundation of threshold signature schemes used in institutional custody, joint accounts, and layer-2 protocols.

Layer-2 Protocols

Lightning Network channels, Spark, and other layer-2 systems build on OP_CHECKSIG to enforce off-chain state transitions. HTLCs combine OP_CHECKSIG with timelocks and hash checks to create conditional payment paths. For an overview of how these layers scale Bitcoin, see the layer-2 scaling landscape research.

Covenant and Advanced Scripts

Proposed opcodes like OP_VAULT and OP_CAT would work alongside OP_CHECKSIG to enable covenants: spending conditions that restrict where bitcoin can be sent next. These proposals rely on OP_CHECKSIG as the base authorization primitive. For more on Bitcoin's programmability, see the Bitcoin Script programmability research.

Risks and Considerations

Historical Bugs

OP_CHECKSIG's legacy implementation carries several consensus-locked quirks that cannot be fixed without a hard fork:

  • SIGHASH_SINGLE bug: when the input index exceeds the number of outputs, the sighash algorithm returns a fixed value (0x0000...0001) instead of failing. This allows a "universal" signature that validates for any transaction in that context.
  • FindAndDelete complexity: the legacy scriptCode preparation uses a FindAndDelete function that removes signature bytes from the script. This enabled O(n²) memory attacks with crafted scripts. SegWit v0 eliminated FindAndDelete for witness scripts, and Tapscript removed it entirely.
  • Signature malleability: before BIP 66 (strict DER encoding) and the low-S standardness rule, third parties could alter a signature's encoding without invalidating it, changing the transaction ID. This was a key motivation for SegWit.

Nonce Reuse

ECDSA signature security depends on a unique random nonce for each signing operation. If the same nonce is reused for two different signatures with the same private key, the private key can be algebraically recovered. This is not a flaw in OP_CHECKSIG itself but a critical requirement for wallet implementations. Deterministic nonce generation (RFC 6979) mitigates this risk.

Quantum Computing Threat

Both ECDSA and Schnorr signatures rely on the difficulty of the elliptic curve discrete logarithm problem. A sufficiently powerful quantum computer running Shor's algorithm could break these schemes. Hash-based output types (P2PKH, P2WPKH) offer partial protection because the public key is only revealed at spend time, but P2PK outputs (where the public key is already exposed) would be immediately vulnerable.

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.