TeachMeBitcoin

P2PK (Pay-to-Public-Key) — simplest form

From TeachMeBitcoin, the free encyclopedia Reading time: 3 min

8. OP_CHECKSIG — The Core Signature Opcode

Overview

OP_CHECKSIG is the most fundamental authorization mechanism in Bitcoin Script. It verifies that a cryptographic signature is valid for the current transaction and the provided public key. It is used in virtually every Bitcoin transaction.

Opcode value: 0xac (decimal 172)
Stack input: <signature> <pubkey> (top of stack)
Stack output: 0x01 (success) or 0x00 (failure)

Basic Script Pattern

# P2PK (Pay-to-Public-Key) — simplest form
scriptPubKey: <pubkey> OP_CHECKSIG
scriptSig:    <signature>

# Execution:

Stack: [ ]

PUSH pubkey: [ <sig> | <pubkey> ]
OP_CHECKSIG: [ 0x01 ]  (if sig valid)

What OP_CHECKSIG Consumes from the Stack

OP_CHECKSIG pops exactly two elements:

Stack before: [ ... | <signature> | <pubkey> ]
                                   ↑ top of stack

Pops: pubkey (first pop)
Pops: signature (second pop)

Processes: Validate sig against pubkey and transaction commitment
Pushes: 0x01 (valid) or 0x00 (invalid)

Historical Context

In the very first Bitcoin transactions (coinbase outputs in early blocks), Satoshi used P2PK scripts — the simplest form using OP_CHECKSIG:

# Satoshi's coinbase output (Block 0 — genesis block)
scriptPubKey:
  04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb
  649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f
  OP_CHECKSIG

This is an uncompressed public key (65 bytes) with OP_CHECKSIG. The 50 BTC from the genesis block are unspendable due to a quirk in the original code, but the script format is the purest form of OP_CHECKSIG usage.

Elliptic Curve Digital Signature Algorithm (ECDSA)

Bitcoin uses ECDSA on the secp256k1 curve for signatures verified by OP_CHECKSIG:

# Key parameters
curve: secp256k1
p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
    FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F
G = generator point (fixed by spec)
n = order of G (number of valid private keys)

# Signing
private_key = d (256-bit integer)
public_key  = d * G (point on curve)

# Signature generation
k = random nonce (CRITICAL: must be unique per signature)
R = k * G
r = R.x mod n
s = k⁻¹ * (hash + r * d) mod n
signature = (r, s)

Taproot: Schnorr Signatures and OP_CHECKSIG

In Taproot (BIP 341, activated November 2021), OP_CHECKSIG in Tapscript validates Schnorr signatures instead of ECDSA:

# Tapscript OP_CHECKSIG context
# Signature is 64 bytes (Schnorr) instead of 71-73 bytes (DER ECDSA)
# Public key is 32 bytes (x-only) instead of 33 bytes (compressed)

scriptPubKey (Tapscript): <32-byte-x-only-pubkey> OP_CHECKSIG
witness:                  <64-byte-schnorr-signature>

Schnorr signatures have several advantages:

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