Understanding Bitcoin Script
What Is Bitcoin Script?
Every time you send Bitcoin, you are not really moving a coin from one place to another. You are creating an output and attaching a small program to it. That program defines the exact conditions under which those coins can later be spent. The language used to write these programs is called Bitcoin Script.
Satoshi Nakamoto described it best, calling a script a kind of predicate: a small equation that evaluates to either true or false. If the spender can make the equation come out true, the coins move. If not, they stay locked. That is the whole job of Script. It is a locking mechanism, not a general computer.
Bitcoin Script is deliberately small and limited. It is not Turing-complete, which means it has no loops, no recursion, and no way to run an open-ended program. This is not a missing feature. It is a core safety decision. A language that cannot loop forever can always be checked quickly and cheaply by every node in the network, which is part of what lets ordinary people verify Bitcoin on modest hardware.
This sits in deliberate contrast to networks that run a Turing-complete contract language. That added expressiveness has repeatedly produced unexpected behavior, frozen funds, and exploits that drained hundreds of millions of Euro or Dollar worth of value. On those platforms, tokens can also be frozen or seized by the issuer or a controlling organization. Bitcoin chose a smaller, predictable language precisely so that no one holds that kind of switch over your coins.
If you have not yet read how a transaction is checked by the network, How Bitcoin Transactions Are Verified is a useful companion to this article.
The Stack: How Script Thinks
Bitcoin Script is a stack-based language. A stack is a simple pile of data where you can only add an item to the top (a "push") or take an item off the top (a "pop"). The last thing you put on is the first thing you take off. Computers handle this kind of memory very efficiently, even if it reads a little oddly to humans.
Because of the stack, Script is not written the way we usually write maths. Instead of writing 9 plus 12, you write the two numbers first and then the operation: 9 12 OP_ADD. The two numbers get pushed onto the stack, and then OP_ADD pops them both off, adds them, and pushes the result back.
The commands like OP_ADD are called opcodes, short for operation codes. They are the verbs of the language. There are around 80 active opcodes, covering simple maths, comparisons, cryptographic hashing, and signature checking. Each one pops some items off the stack, does its job, and may push a result back.
Here is a complete, if slightly silly, example of a working script:
9 12 OP_ADD 21 OP_EQUAL
Reading left to right: push 9, push 12, then OP_ADD replaces them with 21. Now push another 21. Finally OP_EQUAL pops the two values, sees that they match, and pushes a 1. A single 1 is left on the stack, so the script is valid. In plain terms, this output is locked behind the puzzle "give me two numbers that add up to 21," and anyone who can do basic arithmetic could unlock it.
Locking Scripts and Unlocking Scripts
In Bitcoin, that single script is actually split into two halves that live in different places.
The locking script, technically the scriptPubKey, is attached to an output. It sets the conditions for spending. In the example above, the locking part is OP_ADD 21 OP_EQUAL, the rule that must be satisfied.
The unlocking script, technically the scriptSig, is supplied later by whoever wants to spend that output. It provides the input values that satisfy the rule. In the example, the unlocking part is the 9 12, the answer to the puzzle.
So sending someone Bitcoin really means creating an output whose locking script only that person can satisfy. The classic version locks coins to a key, so only the holder of the matching private key can produce a valid unlocking script.
One detail trips up almost everyone. Even though the unlocking script is provided by the spender after the output already exists, when a node runs the full validation it places the unlocking script first, then the locking script. The unlocking script lays the data on the stack, and the locking script then checks it.
How Locking and Unlocking Fit Together
Unlocking Script
scriptSig
Provided by the spender.
Locking Script
scriptPubKey
Attached to the output.
During validation the unlocking script runs first, then the locking script.
If the combined script leaves a single TRUE on the stack, the output is unlocked.
How a Script Gets Validated
A node validates a transaction by combining the unlocking and locking scripts and running them from left to right. The outcome is binary.
A script is valid if, after it finishes, there is exactly one non-zero element left on the stack. In practice that means a single OP_1, or any value that counts as "true."
A script is invalid if the stack is empty at the end, if the only thing left is a zero, if more than one element remains, or if the script aborts early. There is no "maybe." Either the conditions are met or the coins do not move.
This pass-or-fail clarity is what makes Bitcoin verifiable. Every node runs the same scripts and reaches the same answer, with no ambiguity and no dependence on outside information.
Pay-to-Public-Key: The Original Lock
The earliest standard script type is Pay-to-Public-Key (P2PK). The locking script simply contains a public key followed by the opcode OP_CHECKSIG. To spend, the owner provides a signature in the unlocking script.
Locking: <PublicKey> OP_CHECKSIG
Unlocking: <Signature>
OP_CHECKSIG pops the signature and the public key, verifies that the signature was produced by the matching private key, and pushes a 1 if it checks out. P2PK appears in many of the very first blocks, including the coinbase outputs of the genesis block.
Almost nobody uses P2PK today. The problem is practical: to pay someone, you would need their full public key, which is long, unreadable, and easy to copy wrong. Satoshi solved this with the next pattern.
Pay-to-Public-Key-Hash: The Workhorse
Pay-to-Public-Key-Hash (P2PKH) stores only a hash of the public key in the locking script rather than the key itself. Think of the hash as a short fingerprint of the key. The actual public key is revealed only later, in the unlocking script, when the coins are spent.
The hash is produced by running SHA-256 and then RIPEMD-160, a combination Bitcoin wraps into a single opcode called OP_HASH160. The result is only 160 bits, much shorter than the public key. From that hash, with some encoding and a checksum, a wallet builds the familiar Bitcoin address. A useful detail to sit with: addresses do not actually exist inside the blockchain. They are a convenience created by wallets on top of these hashes. The hash is what the protocol sees.
The trade-off is that the public key is no longer visible in the output, yet OP_CHECKSIG needs it to verify the signature. So the spender must supply both the public key and the signature, and the script first checks that the supplied key really does hash to the value stored in the lock.
Locking: OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Unlocking: <Signature> <PublicKey>
For more on the hashing step itself, see What Is a Hash?.
Walking Through a P2PKH Script
Here is the full P2PKH script running step by step. The unlocking script goes first.
- The signature and the public key are pushed onto the stack.
OP_DUPduplicates the top item, the public key, because the script needs one copy to hash and one copy to verify the signature later.OP_HASH160takes the top copy of the public key and hashes it, leaving a fresh public key hash on the stack.- The expected hash from the locking script is pushed on, and
OP_EQUALVERIFYcompares the two hashes. If they differ, the script fails immediately. If they match, both are removed and execution continues. - What remains is now effectively a P2PK script: a signature and a public key.
OP_CHECKSIGverifies the signature against the key and pushes a 1.
A single 1 is left on the stack, so the output is unlocked. The mechanics are identical whether the coins were locked with legacy P2PKH or with its modern SegWit equivalent, P2WPKH. Only the storage location of the signature data changes.
P2PKH Script Execution
Step through how a node unlocks a Pay-to-Public-Key-Hash output.
Stack (top to bottom)
Operation
Initial State
The script is ready. The unlocking script runs first, then the locking script.
Multisignature Scripts
One of Script's most useful tricks is requiring more than one signature to spend. A standard multisig script, type P2MS, encodes an "m of n" rule: out of n listed public keys, any m valid signatures will unlock the funds.
A 2-of-3 multisig, for example, needs 2 signatures from a set of 3 keys. This is the foundation of shared custody, where no single key can move the money on its own. It underpins the multi-signature setups covered in our security articles.
Locking: OP_2 <PubKey1> <PubKey2> <PubKey3> OP_3 OP_CHECKMULTISIG
Unlocking: <Signature1> <Signature2>
OP_CHECKMULTISIG checks both that the required number of valid signatures is present and that each one belongs to one of the listed keys. Written out directly like this, though, multisig has the same awkwardness as P2PK. The sender has to know every public key and the exact script, the output becomes large and expensive, and your security setup is exposed on-chain for everyone to see. The next pattern fixes all of that at once.
Pay-to-Script-Hash: Hiding the Complexity
Pay-to-Script-Hash (P2SH) lets you lock coins to the hash of a script instead of to the script itself. Your full custom script, called the redeem script, stays hidden until you spend.
When sending to a P2SH output, the locking script holds only the hash. The sender does not need to know your multisig layout or your custom conditions. They just pay to a short address that begins with the digit 3. Your redeem script, along with the data that satisfies it, is supplied only later in the unlocking script.
Locking: OP_HASH160 <ScriptHash> OP_EQUAL
Unlocking: <Signature1> <Signature2> <RedeemScript>
Validation happens in two stages. First the outer script confirms that the supplied redeem script hashes to the value in the lock. Then the redeem script is unpacked and run as a script in its own right, against the signatures provided. Only if both stages pass do the coins move. P2SH gives you three wins together: smaller and cheaper outputs, a clean standardized address, and your conditions kept private until the moment you spend.
The Standard Script Types
Although you can build almost any locking script you like, most nodes will only relay a small set of standard patterns. The table below lays out the script types that have shaped Bitcoin, from the legacy era through SegWit and Taproot, with their address prefixes and where each one stores its unlocking data.
The split between legacy and SegWit matters. Legacy scripts (P2PK, P2PKH, P2MS, P2SH) put their unlocking data in the scriptSig. SegWit scripts (P2WPKH, P2WSH, P2TR) put it in a separate witness field instead, which is what fixed transaction malleability and lowered fees.
Standard Script Types
| Type | Pattern | Address | Unlocking | Era |
|---|---|---|---|---|
P2PK Pay to Public Key | <PubKey> OP_CHECKSIG | none | scriptSig | Legacy |
P2PKH Pay to Public Key Hash | OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG | 1... | scriptSig | Legacy |
P2MS Bare Multisig | OP_m <PubKey> ... <PubKey> OP_n OP_CHECKMULTISIG | none | scriptSig | Legacy |
P2SH Pay to Script Hash | OP_HASH160 <ScriptHash> OP_EQUAL | 3... | scriptSig | Legacy |
P2WPKH Pay to Witness Public Key Hash | OP_0 <PubKeyHash> | bc1q... | witness | SegWit |
P2WSH Pay to Witness Script Hash | OP_0 <ScriptHash> | bc1q... | witness | SegWit |
P2TR Pay to Taproot | OP_1 <TaprootOutputKey> | bc1p... | witness | Taproot |
P2PK
Pay to Public Key
Pattern
<PubKey> OP_CHECKSIG
Address
noneUnlocking
scriptSigP2PKH
Pay to Public Key Hash
Pattern
OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Address
1...Unlocking
scriptSigP2MS
Bare Multisig
Pattern
OP_m <PubKey> ... <PubKey> OP_n OP_CHECKMULTISIG
Address
noneUnlocking
scriptSigP2SH
Pay to Script Hash
Pattern
OP_HASH160 <ScriptHash> OP_EQUAL
Address
3...Unlocking
scriptSigP2WPKH
Pay to Witness Public Key Hash
Pattern
OP_0 <PubKeyHash>
Address
bc1q...Unlocking
witnessP2WSH
Pay to Witness Script Hash
Pattern
OP_0 <ScriptHash>
Address
bc1q...Unlocking
witnessP2TR
Pay to Taproot
Pattern
OP_1 <TaprootOutputKey>
Address
bc1p...Unlocking
witnessP2PK and bare P2MS have no standard address format. Multisig is almost always wrapped in P2SH or P2WSH today.
SegWit and Taproot: Beyond Classic Script
The SegWit upgrade in 2017 moved signature data out of the main transaction body and into the witness field. This solved a long-standing problem called transaction malleability, where the visible signature could be tweaked to change a transaction's identifier without changing its meaning, and it also made signature data cheaper to include. P2WPKH and P2WSH are simply the SegWit versions of P2PKH and P2SH, producing addresses that start with bc1q.
Interestingly, these newer script types barely use the full Script language at all. Each follows a fixed internal pattern that nodes execute in a set way, which is exactly the "just check a key and a signature" simplification that classic Script made possible but did not enforce. The full language still lives on inside P2WSH, where you can wrap any custom script you need.
Pay-to-Taproot (P2TR), activated in November 2021, is the newest standard and produces addresses starting with bc1p. It pairs Schnorr signatures with a structure called MAST (Merkelized Abstract Syntax Trees), which lets you encode many alternative spending conditions in a tree. Crucially, only the branch you actually use is revealed when you spend. A wallet with elaborate backup and recovery conditions can therefore spend in a way that looks identical to an ordinary single-key payment, which improves both privacy and efficiency.
Beyond Signatures: Timelocks and Puzzles
Script can express far more than "prove you own this key." Two opcodes add the dimension of time. OP_CHECKLOCKTIMEVERIFY (introduced in BIP 65) makes an output unspendable until a chosen date or block height. OP_CHECKSEQUENCEVERIFY (BIP 112) enforces a relative delay, measured from when the coins were received. Together they make conditions like "these funds cannot move for six months" enforceable by the protocol itself.
These timelocks are the building blocks of more advanced constructions. A Hash Time Locked Contract (HTLC), for instance, combines a hash puzzle with a timelock so a payment either completes when a secret is revealed or refunds after a deadline. That pattern is what makes the Lightning Network possible.
Script also allows pure puzzles. A hash puzzle locks coins behind "provide data that hashes to this value." There is even a hash collision puzzle that pays out to anyone who can supply two different inputs producing the same hash, effectively a public bounty on a broken hash function. And the special opcode OP_RETURN lets you attach a small piece of data to an output while marking it permanently unspendable, a clean way to anchor information into the chain without bloating the set of spendable coins.
The Limits That Keep Bitcoin Safe
Script comes with strict size limits, and they exist for the same reason the language avoids loops: to keep verification fast and to stop anyone from weaponizing it against the network.
The hard validity limits are clear. A complete script cannot exceed 10,000 bytes. It can execute at most 201 opcodes, not counting the operations that simply push data. No single element pushed onto the stack may exceed 520 bytes, and the stack itself may not hold more than 1,000 items at once. Break any of these and the script is invalid, full stop.
There is a softer layer too. A script can be perfectly valid yet non-standard, meaning nodes will refuse to relay it across the network even though a miner could still include it in a block. This is a safety measure: only the well-tested standard patterns get passed around freely, so an attacker cannot flood the network with strange scripts that are slow to verify. Practically, a non-standard transaction has to be handed straight to a miner or mined by you.
Why This Matters
It is tempting to see Script's limits as Bitcoin lagging behind more "programmable" chains. The opposite is true. Every restriction here is a deliberate trade of expressiveness for predictability, verifiability, and safety.
Because no script can loop forever, every node can confirm the entire chain without trusting anyone. Because the language is small, the attack surface is small. Because there is no global shared state that contracts can reach into, there is no single point where someone can reach in and freeze your coins. The very flexibility that lets other networks promise more is also what has let them suffer catastrophic exploits and lets controlling parties seize or freeze balances at will.
Bitcoin made a different bet. A modest, predictable language, checked the same way by everyone, protecting a fixed and neutral set of rules. That is what lets a canoe move on open water without asking permission, which is exactly the point. For the wider picture of how these rules are enforced across the network, see Bitcoin's Consensus Mechanism: A Deep Dive, and for the structure the scripts ultimately protect, What Is a Blockchain?.
Key Facts
Bitcoin Script is non-Turing-complete by design. It has no loops and no recursion, so every script finishes in a bounded, predictable number of steps.
→ See the full tableEvery output carries a locking script (scriptPubKey). To spend it, the transaction must provide a matching unlocking script (scriptSig, or the witness field for SegWit).
A script is valid when execution leaves a single non-zero value on the stack. Anything else fails.
A single Bitcoin script is capped at 10,000 bytes and at most 201 executed opcodes, with no data element larger than 520 bytes.
P2WPKH (native SegWit, 2017) and P2TR (Taproot, 2021) are the modern standard script types and are unlocked through the witness field rather than the scriptSig.
Frequently Asked Questions
No, and that is intentional. Bitcoin Script is non-Turing-complete, which means it cannot run loops or arbitrary programs. This design choice removes whole categories of bugs and makes every transaction quick and cheap to verify, even on modest hardware.
The scriptPubKey is the locking script attached to an output. It sets the conditions that must be met to spend those coins. The scriptSig is the unlocking script provided by the spender. It supplies the data, usually a signature and a public key, that satisfies those conditions.
Yes. Bitcoin Script supports puzzles, timelocks, and multi-signature conditions far beyond a simple signature check. Custom scripts are valid and can be mined, but most nodes only relay a small set of standard patterns, so a non-standard script is harder to get confirmed unless it is wrapped inside P2SH or P2WSH.
Taproot introduced Pay-to-Taproot (P2TR), which pairs Schnorr signatures with a tree of possible spending conditions called MAST. Only the branch you actually use is revealed on-chain, so a complex contract looks identical to a simple payment, improving both privacy and block space efficiency.
Sources
- 1.Greg Walker: Bitcoin Script (learnmeabitcoin.com)
- 2.Antonopoulos: Mastering Bitcoin, Chapter 7, Authorization and Authentication
- 3.Bitcoin Wiki: Script and Opcode List
- 4.BIP 16: Pay to Script Hash
- 5.BIP 141: Segregated Witness
- 6.BIP 341 and BIP 342: Taproot and Tapscript
Not financial advice. CanoeBit publishes educational content only. Nothing here is a recommendation to buy, sell, or hold any asset.
Continue the How Bitcoin Works path
Step 9 of 11