Chapter 11

Script

Bitcoin's Stack-Based Programming Language

Bitcoin transactions do not simply transfer value from one public key to another. Instead, they lock value to programs written in a simple stack-based language called Script. Understanding Script is essential for comprehending how Bitcoin enforces spending conditions and enables advanced features like multisignature wallets and time-locked contracts.

Script is intentionally limited: it is not Turing-complete, has no loops, and every program terminates in bounded time. These restrictions make transaction validation predictable and prevent denial-of-service attacks.

11.1 The Execution Model

Script programs operate on two stacks: the main stack and an auxiliary "alt" stack. Execution proceeds by reading opcodes (operation codes) and data from the script, manipulating the stacks accordingly.

Definition 11.1 (Script Execution)

A script is a sequence of opcodes and data pushes. Execution:

  1. Begins with an empty main stack
  2. Processes each element left-to-right
  3. Data elements are pushed onto the stack
  4. Opcodes consume and produce stack elements
  5. Succeeds if the final stack is non-empty and the top element is true (nonzero)
Main Stack elem 1 elem 2 elem 3 ← top Script (left to right) done done current next ... affects stack
Figure 11.1: Script execution processes elements left-to-right, manipulating the stack.

11.1.1 Script Concatenation

To validate a transaction input, the scriptSig (unlocking script) is concatenated with the scriptPubKey (locking script) of the referenced output, then executed.

Definition 11.2 (Script Validation)

For legacy (pre-SegWit) transactions, validation executes:

scriptSig || scriptPubKey

The transaction input is valid if and only if execution succeeds and leaves a true value on the stack.

Remark 11.1 (Separate Execution)

Historically, scriptSig and scriptPubKey were concatenated and run together. Due to security concerns (malicious scriptSigs could manipulate the stack before scriptPubKey runs), modern implementations execute them separately: scriptSig first, then scriptPubKey operates on the resulting stack.

11.2 Data Push Operations

Non-opcode bytes in a script represent data to be pushed onto the stack. The length of the data determines the push opcode.

Opcode Range Name Effect
0x00 OP_0 / OP_FALSE Push empty byte array (falsy)
0x01–0x4b (direct push) Push next N bytes (N = opcode value)
0x4c OP_PUSHDATA1 Next byte is length; push that many bytes
0x4d OP_PUSHDATA2 Next 2 bytes are length (little-endian)
0x4e OP_PUSHDATA4 Next 4 bytes are length (little-endian)
0x4f OP_1NEGATE Push the number −1
0x51–0x60 OP_1 through OP_16 Push the number 1–16

Example 11.1 (Data Push)

To push the 20-byte hash 89abcdef...12345678:

14 89abcdef...12345678
↑  └──────────────────┘
│         20 bytes
└─ opcode 0x14 = 20 (push 20 bytes)

11.3 Stack Manipulation Opcodes

These opcodes rearrange elements on the stack without performing computation.

Opcode Name Effect
0x76 OP_DUP Duplicate top element
0x75 OP_DROP Remove top element
0x7c OP_SWAP Swap top two elements
0x77 OP_NIP Remove second element
0x78 OP_OVER Copy second element to top
0x79 OP_PICK Copy element at depth n to top
0x7a OP_ROLL Move element at depth n to top
0x73 OP_IFDUP Duplicate top if nonzero
0x74 OP_DEPTH Push stack depth
Before OP_DUP A B OP_DUP After OP_DUP A B B ← copy
Figure 11.2: OP_DUP duplicates the top stack element.

11.4 Arithmetic Opcodes

Script supports limited arithmetic on 32-bit signed integers.

Opcode Name Effect
0x93 OP_ADD a + b
0x94 OP_SUB a − b
0x8b OP_1ADD a + 1
0x8c OP_1SUB a − 1
0x8f OP_NEGATE −a
0x90 OP_ABS |a|
0x9a OP_MIN min(a, b)
0x9b OP_MAX max(a, b)
0xa0 OP_WITHIN min ≤ x < max

Remark 11.2 (Disabled Opcodes)

OP_MUL, OP_DIV, OP_MOD, and bitwise operations were disabled early in Bitcoin's history due to potential implementation bugs. They remain reserved but cause script failure if encountered.

11.5 Cryptographic Opcodes

The most important opcodes perform cryptographic operations.

11.5.1 Hash Functions

Opcode Name Effect
0xa9 OP_HASH160 RIPEMD160(SHA256(top))
0xaa OP_HASH256 SHA256(SHA256(top))
0xa7 OP_SHA1 SHA1(top)
0xa8 OP_SHA256 SHA256(top)
0xa6 OP_RIPEMD160 RIPEMD160(top)

11.5.2 Signature Verification

Opcode Name Effect
0xac OP_CHECKSIG Verify signature against public key
0xad OP_CHECKSIGVERIFY OP_CHECKSIG + OP_VERIFY
0xae OP_CHECKMULTISIG Verify m-of-n multisignature
0xaf OP_CHECKMULTISIGVERIFY OP_CHECKMULTISIG + OP_VERIFY

Definition 11.3 (OP_CHECKSIG)

OP_CHECKSIG pops a public key and signature from the stack. It verifies that the signature is valid for the transaction (as determined by the sighash type) under that public key. It pushes OP_TRUE (1) on success or OP_FALSE (empty array) on failure.

11.6 Flow Control

Script supports conditional execution (but not loops).

Opcode Name Effect
0x63 OP_IF Execute following if top is true
0x64 OP_NOTIF Execute following if top is false
0x67 OP_ELSE Alternative branch
0x68 OP_ENDIF End conditional block
0x69 OP_VERIFY Fail if top is false, else remove it
0x6a OP_RETURN Immediately fail (marks output unspendable)

Example 11.2 (Conditional Script)

OP_IF
    <pubkey_A>
OP_ELSE
    <pubkey_B>
OP_ENDIF
OP_CHECKSIG

This script allows spending with either key A (if the condition is true) or key B (if false). The spender provides a boolean value before their signature.

11.7 Time Lock Opcodes

BIP-65 and BIP-112 introduced opcodes for time-based spending conditions.

Opcode Name BIP Effect
0xb1 OP_CHECKLOCKTIMEVERIFY BIP-65 Fail if current time/height < top of stack
0xb2 OP_CHECKSEQUENCEVERIFY BIP-112 Fail if relative time since UTXO creation < top

Example 11.3 (Time-Locked Output)

An output that can only be spent after block 800,000:

<800000> OP_CHECKLOCKTIMEVERIFY OP_DROP
OP_DUP OP_HASH160 <pubkey_hash> OP_EQUALVERIFY OP_CHECKSIG

The OP_DROP removes the lock time from the stack after verification, then standard P2PKH logic follows.

11.8 Standard Script Templates

While Script allows arbitrary programs, nodes relay only "standard" transactions using recognized templates.

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

Definition 11.4 (P2PKH Scripts)

ScriptPubKey (locking):

OP_DUP OP_HASH160 <20-byte-hash> OP_EQUALVERIFY OP_CHECKSIG

ScriptSig (unlocking):

<signature> <pubkey>
P2PKH Script Execution 1. Push sig, pubkey sig pubkey 2. OP_DUP sig pubkey pubkey 3. OP_HASH160 sig pubkey hash 4. Push expected sig pubkey hash exp_hash 5. OP_EQUALVERIFY sig pubkey ✓ match! 6. OP_CHECKSIG TRUE Execution succeeds: signature valid, hash matches
Figure 11.3: Step-by-step execution of a P2PKH script.

11.8.2 P2SH (Pay-to-Script-Hash)

Definition 11.5 (P2SH Execution)

P2SH scripts are evaluated in two phases:

  1. Verify that the provided redeem script hashes to the expected value
  2. Execute the redeem script with the remaining stack elements

ScriptPubKey:

OP_HASH160 <20-byte-hash> OP_EQUAL

ScriptSig:

<...signatures...> <redeem_script>

11.8.3 Multisignature

Definition 11.6 (m-of-n Multisig)

An m-of-n multisignature script requires m valid signatures from a set of n public keys:

OP_m <pubkey_1> ... <pubkey_n> OP_n OP_CHECKMULTISIG

Remark 11.3 (Off-by-One Bug)

OP_CHECKMULTISIG has a historical bug: it pops one extra element from the stack beyond what's needed. The scriptSig must include a dummy OP_0 at the beginning to account for this.

11.9 OP_RETURN and Data Embedding

OP_RETURN creates a provably unspendable output, useful for embedding arbitrary data in the blockchain.

Definition 11.7 (OP_RETURN Output)

An OP_RETURN output has a scriptPubKey beginning with OP_RETURN followed by up to 80 bytes of data. Such outputs:

  • Are provably unspendable (execution always fails)
  • Can be pruned from the UTXO set
  • Should have zero value

Example 11.4 (Data Embedding)

To embed the text "Hello, Bitcoin!" in the blockchain:

OP_RETURN 48656c6c6f2c20426974636f696e21
          └─────────────────────────────┘
             "Hello, Bitcoin!" in hex

11.10 SegWit Script Execution

Native SegWit outputs use a different execution model. The scriptPubKey is a "witness program," and the actual unlocking data is in the witness field.

Definition 11.8 (Witness Program)

A witness program is a scriptPubKey of the form:

<version> <program>

where version is OP_0 through OP_16, and program is 2–40 bytes.

Version Program Length Interpretation
0 20 bytes P2WPKH: witness = [sig, pubkey]
0 32 bytes P2WSH: witness = [..., witness_script]
1 32 bytes P2TR: Taproot (Schnorr or Tapscript)

11.11 Tapscript

Taproot (BIP-341, BIP-342) introduces Tapscript, an upgraded Script with several improvements.

Definition 11.9 (Tapscript Changes)

Tapscript differs from legacy Script:

  • OP_CHECKSIG uses Schnorr signatures (BIP-340)
  • OP_CHECKMULTISIG is disabled; use OP_CHECKSIGADD instead
  • OP_SUCCESS opcodes allow future soft-fork upgrades
  • Signature validation is more efficient (batch verification possible)

Example 11.5 (Tapscript Multisig)

A 2-of-3 multisig in Tapscript:

<pubkey_1> OP_CHECKSIG
<pubkey_2> OP_CHECKSIGADD
<pubkey_3> OP_CHECKSIGADD
OP_2 OP_NUMEQUAL

Each OP_CHECKSIGADD adds 1 to a running counter if the signature is valid, enabling clean m-of-n without the legacy off-by-one bug.

11.12 Script Limitations

Script's restrictions are intentional, ensuring predictable validation.

Theorem 11.1 (Script Termination)

Every valid Script program terminates. The maximum number of operations is bounded by:

  • Maximum script size: 10,000 bytes
  • Maximum stack size: 1,000 elements
  • Maximum element size: 520 bytes
  • Maximum opcode count: 201 (non-push operations)

These limits ensure that script validation has bounded time and space complexity, preventing denial-of-service attacks.

Exercises

Exercise 11.1

Trace the execution of the following script with initial stack [3, 5]:

OP_ADD OP_6 OP_EQUAL

Does execution succeed or fail?

Exercise 11.2

Write a script that allows spending if the spender provides two numbers whose product is 42. (Note: OP_MUL is disabled, so you'll need a workaround.)

Exercise 11.3

Explain why Script is not Turing-complete. What feature would need to be added to make it Turing-complete, and why would this be problematic?

Exercise 11.4

A P2SH output encodes a 2-of-3 multisig. Write out both the scriptPubKey and a valid scriptSig (with placeholder signatures).

Exercise 11.5

Why is OP_RETURN important for the UTXO set? What would happen if users embedded data in spendable outputs instead?