Bitcoin Script & opcodes

The tiny stack language that locks every coin.

Coins are not stored in accounts. Each UTXO carries a small program, the locking script (scriptPubKey), that says what is needed to spend it. The spender provides an unlocking script (scriptSig, or the witness for SegWit). A node runs them and, if the result is "true", the spend is valid.

A stack machine

Script is read left to right. Data is pushed onto a stack, and each opcode pops items, works on them and pushes results. There are no loops, which means every script finishes, and its cost is predictable. This is deliberate: Script is not Turing-complete.

Walking through P2PKH

The classic "pay to public key hash" locking script is:

OP_DUP OP_HASH160 <20-byte pubkey hash> OP_EQUALVERIFY OP_CHECKSIG

The spender supplies <signature> <public key>. The interpreter:

  1. pushes the signature and public key,
  2. duplicates the public key (OP_DUP),
  3. hashes the copy with SHA-256 then RIPEMD-160 (OP_HASH160),
  4. checks it equals the hash in the locking script (OP_EQUALVERIFY),
  5. verifies the digital signature against the key and the transaction (OP_CHECKSIG).

If all steps pass, a "true" is left on the stack and the coin can be spent.

What the signature covers

OP_CHECKSIG does not sign arbitrary bytes. It checks a hash of selected parts of the transaction, chosen by the sighash flag. Usually that is everything, so nobody can change the outputs after you sign.

Limits for safety

Legacy scripts have hard limits: at most 10,000 bytes, at most 201 non-push opcodes, and at most 1,000 items on the stack. Opcodes like OP_CAT were disabled in 2010 after bugs were found. Tapscript (BIP342) dropped the 10,000-byte and 201-opcode limits and relies on a signature budget tied to witness size instead.

Beyond single signatures

The same tools express multisig (OP_CHECKMULTISIG, or OP_CHECKSIGADD in Tapscript), hash locks (OP_SHA256 <hash> OP_EQUAL) and timelocks (OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY). Combining them gives you vaults, inheritance plans and Lightning channels. Writing such scripts by hand is error-prone, which is why Miniscript exists.