Introduction: Bitcoin's Programming Language
Bitcoin is often contrasted with Ethereum—"Bitcoin is money, Ethereum is smart contracts." This framing is misleading. Bitcoin has always had a programming language called Script, enabling sophisticated conditions for spending coins. What Bitcoin doesn't have (by design) is Turing-complete smart contracts with arbitrary state changes.
Bitcoin Script is intentionally simple, deliberately constrained, and carefully designed for security over expressiveness. It enables multisignature wallets, time locks, hash locks, atomic swaps, and increasingly complex spending conditions—all while maintaining Bitcoin's core principles of security, verify ability, and resistance to exploitation.
This article explores Bitcoin Script from foundational concepts to advanced applications, covering the opcodes, common script patterns, modern improvements like Taproot, and the philosophical differences between Bitcoin's scripting model and Ethereum-style smart contracts.
Understanding Bitcoin Script
What is Script?
Bitcoin Script is a stack-based programming language used to define the conditions under which a bitcoin output can be spent. Every Bitcoin transaction output includes a locking script (scriptPubKey) that specifies how the coins can be claimed. To spend those coins, you must provide an unlocking script (scriptSig) that satisfies the conditions.
Key Characteristics
- Stack-based: Operations manipulate a stack (push/pop data structure)
- Not Turing-complete: No loops, guaranteed to terminate
- Forth-like syntax: Postfix notation (operands before operators)
- Deterministic: Same inputs always produce same results
- Stateless: No persistent storage or external state
Why Not Turing-Complete?
Bitcoin deliberately avoids Turing-completeness to ensure:
- Predictable execution costs: No infinite loops, every script terminates quickly
- Analyzability: Can mathematically prove properties about scripts
- Safety: Limited attack surface compared to general-purpose languages
- Simplicity: Easier to audit, less surface for bugs
The nature of Bitcoin is such that once version 0.1 was released, the core design was set in stone for the rest of its lifetime. — Satoshi Nakamoto
Script Execution Model
The Stack
Script uses a last-in-first-out (LIFO) stack. Operations pop values from the stack, perform computations, and push results back:
2 3 OP_ADD
Execution:
- Push 2 onto stack: [2]
- Push 3 onto stack: [2, 3]
- OP_ADD pops 3 and 2, adds them, pushes result: [5]
Script Validation
To spend a Bitcoin output, you combine the unlocking and locking scripts:
- Execute unlocking script (scriptSig) to push data onto stack
- Execute locking script (scriptPubKey) using the stack
- If final stack value is TRUE (non-zero), transaction is valid
Simple Example: Pay-to-Public-Key
Locking script (in output):
<pubkey> OP_CHECKSIG
Unlocking script (in input):
<signature>
Combined execution:
- Push signature onto stack: [sig]
- Push public key onto stack: [sig, pubkey]
- OP_CHECKSIG pops both, verifies signature, pushes TRUE: [TRUE]
Transaction is valid!
Common Script Patterns
Pay-to-Public-Key-Hash (P2PKH)
The original Bitcoin address format. Locking script:
OP_DUP OP_HASH160 <pubkey_hash> OP_EQUALVERIFY OP_CHECKSIG
Unlocking script:
<signature> <pubkey>
This pattern requires the spender to provide both the public key and a valid signature, with the public key hashing to the specified hash.
Pay-to-Script-Hash (P2SH)
Introduced in BIP 16, P2SH allows complex scripts to be represented by a simple hash. The sender pays to a script hash; the recipient must provide the script (redeem script) and data that satisfies it.
Locking script:
OP_HASH160 <script_hash> OP_EQUAL
Unlocking script:
<data> <redeem_script>
This enables multisig wallets, time locks, and complex conditions without bloating the blockchain until spending.
Multisignature (Multisig)
Requires M-of-N signatures. For 2-of-3:
OP_2 <pubkey1> <pubkey2> <pubkey3> OP_3 OP_CHECKMULTISIG
Unlocking:
OP_0 <signature1> <signature2>
(Note: OP_0 is a quirk due to an off-by-one bug in OP_CHECKMULTISIG that's now part of consensus)
Time Locks
Absolute Time Locks: OP_CHECKLOCKTIMEVERIFY (CLTV)
CLTV (BIP 65) prevents a transaction from being spent until a specific block height or Unix timestamp:
<expiry_time> OP_CHECKLOCKTIMEVERIFY OP_DROP
<pubkey> OP_CHECKSIG
This output cannot be spent until block <expiry_time> or later.
Use Cases
CLTV enables powerful use cases. Inheritance planning creates funds that unlock automatically after specified inactivity periods—for example, Bitcoin becoming accessible to heirs if the holder fails to move it for one year. Vesting schedules implement employee compensation that unlocks over time, paying out Bitcoin bonuses only after continued employment through specific dates. Escrow arrangements hold funds that become releasable only after contractual deadlines, ensuring neither party can access disputed funds prematurely.
Relative Time Locks: OP_CHECKSEQUENCEVERIFY (CSV)
CSV (BIP 112) specifies relative time—the output can't be spent until N blocks after it was created:
<blocks> OP_CHECKSEQUENCEVERIFY OP_DROP
<pubkey> OP_CHECKSIG
Use Cases
CSV proves essential for Layer 2 protocols. Lightning Network uses CSV for dispute resolution periods, ensuring cheating parties can be penalized before fraudulent channel states finalize. State channels employ CSV to allow time for challenges—if one party broadcasts an outdated state, counterparties have a window to prove fraud and claim penalties. Payment channels implement unilateral exit with delays using CSV, preventing parties from immediately withdrawing during cooperative operation while maintaining eventual exit guarantees if cooperation fails.
Hash Locks
OP_HASH256 and OP_EQUAL
Hash locks require the spender to provide a preimage that hashes to a specific value:
OP_HASH256 <hash> OP_EQUALVERIFY
<pubkey> OP_CHECKSIG
Unlocking requires:
<signature> <preimage>
The preimage must hash to the specified hash.
Hash Time-Locked Contracts (HTLCs)
Combining hash locks and time locks creates HTLCs, the building block of Lightning Network:
OP_IF
OP_HASH256 <hash> OP_EQUALVERIFY
<alice_pubkey>
OP_ELSE
<timeout> OP_CHECKLOCKTIMEVERIFY OP_DROP
<bob_pubkey>
OP_ENDIF
OP_CHECKSIG
This output can be claimed by:
- Alice with the preimage (anytime)
- Bob after timeout (refund)
Applications
- Atomic swaps: Cross-chain trustless exchanges
- Lightning payments: Routing through intermediaries
- Submarine swaps: On-chain to Lightning exchanges
Taproot: Bitcoin's Smart Contract Upgrade
What is Taproot?
Activated in November 2021 (BIP 340, 341, 342), Taproot represents the most significant Bitcoin protocol upgrade since SegWit. It introduces:
- Schnorr signatures: More efficient and flexible than ECDSA
- MAST (Merklized Alternative Script Trees): Hide unexecuted script paths
- Tapscript: Improved script version with new opcodes
Key Path vs Script Path
Taproot outputs (P2TR) can be spent in two ways:
- Key path: Simple signature (looks like regular payment)
- Script path: Reveal and execute a script from the Merkle tree
This means complex multisig, time locks, and HTLCs can look identical to simple payments on-chain—dramatically improving privacy.
MAST: Hiding Complexity
Traditional scripts reveal all possible spending conditions, even those not used. MAST uses Merkle trees to commit to multiple scripts, revealing only the one executed:
- Create multiple possible spending scripts
- Build Merkle tree from script hashes
- Commit only the Merkle root in the output
- When spending, reveal only the executed branch
Example
A wallet with conditions:
- Script A: 2-of-3 multisig (normal operation)
- Script B: 1-of-3 after 1 year (inheritance)
- Script C: Recovery key (emergency backup)
With MAST, spending via Script A reveals nothing about Scripts B or C. Privacy and efficiency both improve.
Schnorr Signatures and Key Aggregation
Schnorr enables key aggregation: multiple public keys can be combined into a single aggregated key, and multiple signatures combined into a single signature.
Benefits
- Smaller transactions: One signature instead of N signatures
- Lower fees: Less data = cheaper transactions
- Better privacy: Multisig indistinguishable from single-sig
- MuSig protocol: Secure multi-party signing without trusted setup
Advanced Script Patterns
Covenants
Covenants restrict how an output can be spent in future transactions—not just who can spend it, but where the funds can go. While Bitcoin doesn't natively support general covenants, limited forms exist:
- OP_CHECKTEMPLATEVERIFY (CTV): Proposed opcode to commit to future transaction structure
- Vaults: Two-step spending requiring time delay for security
Vault Example
- Cold wallet contains BTC
- To spend, first move to intermediate address (publicly announced)
- Wait 24-48 hours (challenge period)
- If no challenge, complete spend to final destination
- If key compromised, use emergency key to block during challenge period
Discreet Log Contracts (DLCs)
DLCs enable Bitcoin-based conditional payments based on external events (oracles):
- Alice and Bob create a contract based on BTC/USD price
- They pre-sign transactions for all possible outcomes
- Oracle publishes signature for actual outcome
- Winning party can broadcast their pre-signed transaction
This enables derivatives, prediction markets, and insurance—all non-custodially on Bitcoin.
Submarine Swaps
Atomic swaps between on-chain and Lightning using HTLCs:
- Service generates preimage and hash
- You send on-chain BTC to HTLC with that hash
- Service sends Lightning BTC to you
- You claim Lightning payment, revealing preimage
- Service uses preimage to claim on-chain BTC
Trustless, atomic (all or nothing), enables seamless on/off-ramping to Lightning.
Script Opcodes Reference
Arithmetic
- OP_ADD: Add top two stack items
- OP_SUB: Subtract top from second
- OP_MUL: (Disabled)
- OP_DIV: (Disabled)
Cryptographic
- OP_RIPEMD160: RIPEMD-160 hash
- OP_SHA1: SHA-1 hash
- OP_SHA256: SHA-256 hash
- OP_HASH160: SHA-256 then RIPEMD-160 (Bitcoin address hash)
- OP_HASH256: Double SHA-256 (used in block hashing)
- OP_CHECKSIG: Verify signature
- OP_CHECKMULTISIG: Verify M-of-N signatures
Stack Manipulation
- OP_DUP: Duplicate top stack item
- OP_DROP: Remove top stack item
- OP_SWAP: Swap top two items
- OP_PICK: Copy Nth stack item to top
Control Flow
- OP_IF / OP_ELSE / OP_ENDIF: Conditional execution
- OP_RETURN: Mark transaction as invalid (used for data storage)
Time Locks
- OP_CHECKLOCKTIMEVERIFY (CLTV): Absolute time lock
- OP_CHECKSEQUENCEVERIFY (CSV): Relative time lock
Limitations and Tradeoffs
What Bitcoin Script Cannot Do
- Loops: No recursion or iteration (prevents infinite execution)
- State: No persistent storage between transactions
- External calls: Cannot query blockchain state or call other contracts
- Floating point: Only integer arithmetic
- Complex data structures: Limited to stack-based primitives
Why These Limitations Exist
- Predictability: Execution cost must be deterministic
- Security: Limited attack surface
- Simplicity: Easier to audit and reason about
- Conservation: Bitcoin optimizes for being money first
Bitcoin vs. Ethereum: Philosophical Differences
Design Philosophy
Bitcoin:
- Money first, programmability second
- Conservative upgrades, ossification preferred
- Predictable, analyzable, secure
- Simple > complex
Ethereum:
- World computer, general-purpose platform
- Rapid iteration, feature-rich
- Turing-complete, expressive
- Powerful > simple
Security Models
Bitcoin's simplicity enables:
- Formal verification of script properties
- Static analysis of all possible execution paths
- Predictable resource consumption
Ethereum's complexity requires:
- Gas markets to prevent resource exhaustion
- Ongoing security research for new attack vectors
- Constant evolution of best practices
The Future of Bitcoin Script
Proposed Upgrades
- OP_CHECKTEMPLATEVERIFY (CTV): Enable covenants and vaults
- OP_TAPLEAF_UPDATE_VERIFY (TLUV): More flexible covenant primitives
- SIGHASH_ANYPREVOUT: Simplify Lightning Network
- OP_CAT: Concatenate stack items (previously disabled)
Layer 2 Innovation
Rather than expanding base layer script capabilities, Bitcoin increasingly relies on Layer 2:
- Lightning Network: Instant payments with HTLCs
- RGB: Client-side validation for complex contracts
- Stacks: Smart contract layer anchored to Bitcoin
- Liquid: Federated sidechain with confidential transactions
Conclusion: Simple, Powerful, Secure
Bitcoin Script is often dismissed as "too limited" compared to Ethereum. This misses the point. Script is precisely as powerful as it needs to be for Bitcoin's primary purpose: being the most secure, decentralized, and resistant form of money ever created.
The constraints aren't bugs—they're features. Every limitation exists to ensure predictability, analyzability, and security. Every avoided feature is a potential attack vector prevented.
Yet within these constraints, Script enables sophisticated functionality: multisig security, time-locked inheritance, atomic swaps, Lightning Network, DLCs, and more. With Taproot, privacy and efficiency reach new heights while maintaining Script's core principles.
Bitcoin Script is the foundation upon which Bitcoin's programmable money is built—deliberately simple, provably secure, and powerful enough for the job at hand.