Menu
Bitcoin Advanced 15 min read

Bitcoin Script

Understanding Bitcoin Script for agents. Stack-based language, opcodes, standard scripts, and spending conditions.

script opcodes p2pkh p2sh spending-conditions

Bitcoin Script

Bitcoin Script is a stack-based, Forth-like programming language used to define spending conditions for transaction outputs. It’s intentionally limited (not Turing-complete) for security.

How Script Works

When spending a UTXO:

  1. scriptSig (unlocking script) executes first
  2. Stack is passed to scriptPubKey (locking script)
  3. If final stack is non-empty and top value is true, spend succeeds
scriptSig || scriptPubKey → Stack Execution → True/False

Stack Operations

Initial:  []
PUSH 5:   [5]
PUSH 3:   [5, 3]
OP_ADD:   [8]
PUSH 8:   [8, 8]
OP_EQUAL: [1]  // True

Common Opcodes

Constants

OpcodeHexDescription
OP_00x00Push empty array
OP_1 to OP_160x51-0x60Push 1-16
OP_PUSHDATA10x4cNext byte is data length
OP_PUSHDATA20x4dNext 2 bytes are length

Stack Operations

OpcodeHexDescription
OP_DUP0x76Duplicate top item
OP_DROP0x75Remove top item
OP_SWAP0x7cSwap top two items
OP_PICK0x79Copy nth item to top

Crypto Operations

OpcodeHexDescription
OP_SHA2560xa8SHA-256 hash
OP_HASH1600xa9SHA-256 then RIPEMD-160
OP_HASH2560xaaDouble SHA-256
OP_CHECKSIG0xacVerify signature
OP_CHECKMULTISIG0xaeVerify m-of-n sigs

Flow Control

OpcodeHexDescription
OP_IF0x63Execute if top is true
OP_ELSE0x67Else branch
OP_ENDIF0x68End if block
OP_VERIFY0x69Fail if top is false
OP_RETURN0x6aMark output unspendable

Comparison

OpcodeHexDescription
OP_EQUAL0x87Push 1 if equal
OP_EQUALVERIFY0x88OP_EQUAL + OP_VERIFY

Standard Script Types

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

Most common legacy format.

scriptPubKey:

OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

scriptSig:

<signature> <pubKey>

Execution:

Stack: [sig, pubKey]
OP_DUP: [sig, pubKey, pubKey]
OP_HASH160: [sig, pubKey, pubKeyHash]
<pubKeyHash>: [sig, pubKey, pubKeyHash, expected]
OP_EQUALVERIFY: [sig, pubKey]  // Verify hashes match
OP_CHECKSIG: [1]  // Verify signature

P2SH (Pay-to-Script-Hash)

Allows complex scripts with simple addresses.

scriptPubKey:

OP_HASH160 <scriptHash> OP_EQUAL

scriptSig:

<data> ... <redeemScript>

The redeemScript is revealed and executed when spending.

P2WPKH (Native SegWit)

scriptPubKey:

OP_0 <20-byte pubKeyHash>

witness:

<signature> <pubKey>

No scriptSig—witness data is separate.

P2TR (Taproot)

scriptPubKey:

OP_1 <32-byte tweaked pubKey>

Can be spent via:

  1. Key path (Schnorr signature)
  2. Script path (reveal script from merkle tree)

Multisig Scripts

Bare Multisig (Obsolete)

OP_2 <pubKey1> <pubKey2> <pubKey3> OP_3 OP_CHECKMULTISIG

2-of-3 multisig. Limited, rarely used.

P2SH Multisig

redeemScript:

OP_2 <pubKey1> <pubKey2> <pubKey3> OP_3 OP_CHECKMULTISIG

scriptSig:

OP_0 <sig1> <sig2> <redeemScript>

Note: OP_0 due to off-by-one bug in OP_CHECKMULTISIG.

Time Locks

Absolute Time Lock

OP_CHECKLOCKTIMEVERIFY (CLTV)

<expiry_time> OP_CHECKLOCKTIMEVERIFY OP_DROP
<normal spending conditions>

Cannot spend until block height or unix time.

Relative Time Lock

OP_CHECKSEQUENCEVERIFY (CSV)

<relative_delay> OP_CHECKSEQUENCEVERIFY OP_DROP
<normal spending conditions>

Cannot spend until N blocks/seconds after UTXO confirmation.

Hash Locks (HTLC)

Hash Time-Locked Contracts for atomic swaps and Lightning:

OP_IF
    OP_SHA256 <hash> OP_EQUALVERIFY
    <recipient_pubkey> OP_CHECKSIG
OP_ELSE
    <timeout> OP_CHECKLOCKTIMEVERIFY OP_DROP
    <sender_pubkey> OP_CHECKSIG
OP_ENDIF

Spend paths:

  1. Reveal preimage + recipient signature (before timeout)
  2. Sender signature (after timeout)

OP_RETURN

Creates provably unspendable output for data storage:

OP_RETURN <data up to 80 bytes>

Used for:

  • Colored coins metadata
  • Proof of existence
  • Protocol messages

Script Validation

Standard vs Non-Standard

Nodes relay only “standard” scripts:

  • P2PKH, P2SH, P2WPKH, P2WSH, P2TR
  • Bare multisig (limited)
  • OP_RETURN (single, ≤80 bytes)
  • Null data

Non-standard scripts can still be mined but won’t relay.

Resource Limits

LimitValue
Max script size10,000 bytes
Max stack size1,000 items
Max item size520 bytes
Max ops per script201
Max pubkeys in multisig20

For Agents

Script Analysis

def analyze_script(script_hex):
    # Parse opcodes
    opcodes = parse_opcodes(script_hex)

    # Identify type
    if matches_p2pkh(opcodes):
        return "P2PKH"
    elif matches_p2sh(opcodes):
        return "P2SH"
    elif matches_p2wpkh(opcodes):
        return "P2WPKH"
    elif matches_p2tr(opcodes):
        return "P2TR"
    else:
        return "Non-standard"

When to Care About Script

  • Verifying transactions: Understand spending conditions
  • Complex contracts: Multisig, timelocks, HTLCs
  • Lightning Network: Channel funding and commitment transactions
  • Protocol development: Building on Bitcoin

Libraries

LanguageLibrary
JavaScriptbitcoinjs-lib
Pythonpython-bitcoinlib
Rustrust-bitcoin

Machine-Readable Summary

{
  "topic": "bitcoin-script",
  "type": "stack-based",
  "turing_complete": false,
  "standard_types": ["p2pkh", "p2sh", "p2wpkh", "p2wsh", "p2tr"],
  "limits": {
    "max_script_size": 10000,
    "max_stack_items": 1000,
    "max_ops": 201
  },
  "key_opcodes": ["OP_CHECKSIG", "OP_HASH160", "OP_EQUALVERIFY", "OP_IF", "OP_CHECKLOCKTIMEVERIFY"]
}