Script Language

Bitcoin's powerful transaction programming language

Advanced

A Note from Satoshi

Long before I released Bitcoin, I recognized that a digital currency system needed more than just basic transactions. It would require a flexible, programmable foundation that could support evolving use cases while maintaining security and determinism.

The scripting system in Bitcoin wasn't an afterthought—it was a deliberate design decision. I chose a stack-based language with simple operations, drawing inspiration from Forth and other minimalist programming languages. This approach allowed for verification without the security risks of Turing-completeness.

Script is purposefully limited. It can't access the blockchain, previous transactions, or external data. It only answers one question: "Are the conditions for spending these coins satisfied?" This constraint is a feature, not a limitation. By narrowly focusing on validation logic, Script keeps the system secure and predictable while still enabling remarkable flexibility.

While many consider Bitcoin Script arcane or limited today, I built it with an eye to the future. Most of its capabilities remain dormant, waiting for creative minds to unlock new ways of defining ownership and conditional transfers that go far beyond what traditional financial systems can accomplish.

"The design supports a tremendous variety of possible transaction types that I designed in from the beginning. Anyone can create new transaction types by programming Bitcoin Script."

BitcoinTalk ForumJune 17, 2010

Technical Foundation

Bitcoin Script is a stack-based, non-Turing-complete language designed specifically for defining conditions that must be satisfied to spend Bitcoin. Unlike conventional programming languages, Script doesn't use variables, loops, or functions—it operates purely through stack manipulations and predefined operations.

Execution Model

Bitcoin Script uses a simple but powerful execution model:

  • Scripts execute on a stack-based virtual machine
  • Each operation (opcode) manipulates data on a single stack
  • Data is processed in postfix notation (operators follow operands)
  • Script execution is deterministic with no side effects
  • A script succeeds if it completes without errors and leaves TRUE on the stack

Stack-Based Language

Bitcoin Script relies on a data structure called a stack, where elements can only be pushed onto or popped from the top:

// Stack operations example:
1 2 OP_ADD

Stack evolution:
[] -> [1] -> [1, 2] -> [3]

Locking Script (scriptPubKey)

Defines the conditions required to spend the bitcoin. Part of the transaction output.

Example: "Provide a public key hashing to X and a valid signature."

Unlocking Script (scriptSig)

Provides data satisfying the locking script. Part of the transaction input.

Example: "Here's my public key and signature."

Script Execution Process

When a transaction is validated, Bitcoin combines the unlocking and locking scripts:

1

Combine Scripts

The unlocking script (scriptSig) is concatenated with the locking script (scriptPubKey).

validation_script = scriptSig + scriptPubKey
2

Initialize Empty Stack

An empty stack is created.

stack = []
3

Execute Script

Executed left-to-right, each operation pushes data or manipulates the stack.

Operations:

  • Push data
  • Pop values, operate, push result
  • Modify stack elements
  • Conditional evaluation
4

Check Final State

Execution must complete without errors and leave a single TRUE value (non-zero) on the stack.

Success: Stack = [TRUE]
Failure: Stack != [TRUE] or Error

Standard Script Types

While Script allows complex conditions, most Bitcoin transactions use a few standard templates for efficiency and compatibility:

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

The most common type. Locks coins to the hash of a public key.

Locking Script (scriptPubKey):
OP_DUP OP_HASH160 <PublicKeyHash> OP_EQUALVERIFY OP_CHECKSIG

Unlocking Script (scriptSig):
<Signature> <PublicKey>

Requires a valid signature from the public key that hashes to the specified hash.

P2SH (Pay-to-Script-Hash)

Locks coins to the hash of another script (redeemScript).

Locking Script (scriptPubKey):
OP_HASH160 <ScriptHash> OP_EQUAL

Unlocking Script (scriptSig):
...arguments... <redeemScript>

Allows complex scripts (e.g., multisig) without burdening the UTXO set. The redeemScript itself is revealed and executed during spending.

P2WPKH (Pay-to-Witness-Public-Key-Hash)

SegWit version of P2PKH. Uses witness data.

Locking Script (scriptPubKey):
0 <PublicKeyHash (20 bytes)>

Witness Data:
<Signature> <PublicKey>

Moves signature data to the witness field, reducing transaction size and fixing malleability.

P2WSH (Pay-to-Witness-Script-Hash)

SegWit version of P2SH.

Locking Script (scriptPubKey):
0 <ScriptHash (32 bytes)>

Witness Data:
...arguments... <witnessScript>

SegWit equivalent for complex scripts, offering size and malleability benefits.

P2TR (Pay-to-Taproot)

Introduced with Taproot upgrade (BIP 341).

Locking Script (scriptPubKey):
1 <OutputKey (32 bytes)>

Spending Path (Key or Script):
Key path or Script path spending using witness data.

Enhances privacy and efficiency. Allows spending via a key path (looks like P2PKH) or complex script paths (revealed only if used).

OP_RETURN

Creates provably unspendable outputs used for embedding data.

Locking Script (scriptPubKey):
OP_RETURN <Data (up to 80 bytes)>

Allows small amounts of arbitrary data to be stored on the blockchain without polluting the UTXO set.

Script Evolution: SegWit and Taproot

Bitcoin Script has evolved through soft forks like Segregated Witness (SegWit) and Taproot, enhancing efficiency, privacy, and capabilities.

Segregated Witness (SegWit)

Introduced P2WPKH and P2WSH, moving signature data (witness) outside the main transaction block.

+ Lower transaction fees (witness data discounted)
+ Fixes transaction malleability
+ Enables Layer 2 solutions (e.g., Lightning Network)

Taproot (BIP 341, 342)

Introduced P2TR, Schnorr signatures, and TapScript, further improving privacy and script capabilities.

+ Enhanced Privacy (complex scripts look like simple payments)
+ Increased Script Efficiency (batch validation)
+ More Flexible Scripting (TapScript improvements over legacy Script)

Script Capabilities and Limitations

Bitcoin Script includes a broad set of operations but is intentionally limited for security and determinism.

Stack Operations

  • OP_DUP, OP_SWAP, OP_DROP...

Arithmetic & Logic

  • OP_ADD, OP_EQUAL, OP_BOOLAND...

Cryptographic

  • OP_SHA256, OP_CHECKSIG, OP_CLTV...

Deliberate Limitations

No Loops:

Ensures termination, prevents DoS.

No State:

Self-contained, deterministic execution.

No Blockchain Access:

Validation independent of chain state.

Disabled Opcodes:

Precaution against potential exploits (e.g., OP_CAT).

Script Debugging and Analysis

Understanding script execution is crucial:

Script Tracing

Step-by-step execution showing stack changes:

OP_3: [3]
OP_DUP: [3, 3]
OP_ADD: [6]

Testing Resources

  • Bitcoin Core tests
  • Online debuggers
  • btcdeb

Best Practices

Start Simple

Build complexity gradually

Test Thoroughly

Use testnet extensively

Consider Edge Cases

Verify all execution paths

Technical Deep Dive

Technical Deep DiveScript Language
Advanced
Complete verification first