liberlume-content-v3 lang: en title: Bitcoin's locks summary: Every coin on Bitcoin sits behind a lock: the scriptPubKey, the program that states under which conditions it can be spent. A reference piece on the lock types, from the first outputs of 2009 to Taproot and the quantum-resistant proposals: P2PK, P2PKH, bare multisig, P2SH, SegWit (P2WPKH and P2WSH), P2TR, each shown byte by byte on a real transaction verifiable with a node. What each type exposes of the public key, why a lock and an address are not the same thing, and how to read the language of scripts: pushes, ops and the stack. btc-anchor: 961200,000000000000000000011cfa417c07445190afe0a7be85c1c3d8d3ffaf119931 prev: sha256:6e0590b74dd1550cdb0ba04d1b0ad8536521e2aa94ec5ad606443d8e1a800643 --- body --- Every coin on Bitcoin sits behind a lock: a small program, the scriptPubKey, that states under which conditions the coin can be spent. Spending means presenting what the lock asks for, normally a signature proving possession of the right key. The lock types are few, born one after another along the history of the protocol, and each answers the same question in its own way: **how much of what locks the coin can be seen from the outside**. Some locks place the public key in the clear on the output from the first instant; others expose only its hash, and the key shows only when the coin moves. That is what this piece looks at: what shape the locks have, how they changed, what tells one from another. This text stays at the overview level: the chronology of the types, the tables that line them up, and the byte form of each lock. How a whole transaction is actually built and signed, its format piece by piece, is matter for a second, more technical pass. Readers arriving from the pieces on [quantum computing](/en/bitcoin-and-quantum-computing/) and its [measured numbers](/en/bitcoin-and-quantum-computing-data-july-2026/) will find here the mechanism those pieces take as known. ## A lock and an address are not the same thing Best to clear this up right away, because it is the most common misunderstanding. The lock is the scriptPubKey, the script that sits on the output and fixes its spending conditions. The **address** is not the lock: it is just a compact way of writing it, an encoding designed to fit in a message, with an integrity check that keeps a mistyped character from slipping through. From an address the wallet derives the lock to put on the output; on the ledger there are no addresses, there are scripts. Keeping the two apart explains several asymmetries. Some lock types have no address of their own (the oldest ones). Different encodings coexist at the same time, one per family of locks. And the very same address, reused to receive twice, produces two outputs with the same lock: when the first is spent, the key becomes public, and the second finds itself uncovered without anyone having touched it. ## The language of locks A lock is a program, and the language it is written in is called Script: a sequence of instructions, the **ops** (opcodes), executed on a stack of data. Whoever spends presents their unlocking data, normally a signature and a key, sometimes a whole script; nodes put that data on the stack and then run the lock: if "true" is left on the stack at the end, the spend is valid. That is all: there is no gatekeeper deciding, there is a program that every node in the world re-runs and that gives everyone the same outcome. When a block reaches a node, the checks run in a precise order, from cheapest to most expensive: first the header and the proof-of-work, which cost one hash; then the shape of the block; then, for each transaction, that the coins being spent really exist and are not already spent; and only at the end are the locks executed, that is, the signatures verified. It is the step that costs the most, and it comes last on purpose: whoever sends garbage is stopped before making everyone pay for it. For many transactions, moreover, the node has already done that work when it saw them go by, and it remembers. The locks in this piece are that last link. The allowed operations are few and concrete: putting data on the stack, duplicating and comparing it (`OP_DUP`, `OP_EQUAL`), computing its hash (`OP_HASH160`, `OP_SHA256`), verifying signatures (`OP_CHECKSIG`, `OP_CHECKMULTISIG`), opening a branch (`OP_IF`), binding the spend to time (`OP_CHECKLOCKTIMEVERIFY`, `OP_CHECKSEQUENCEVERIFY`). Loops are missing on purpose: a script cannot repeat itself, so every verification is certain to end and costs a predictable amount of time. In 2010, after some flaws were found, part of the ops were disabled (`OP_CAT` and others): the language has been narrower than it was born ever since. The families, in a table; the locks of the chronology all live in the first five rows. | family | main ops | what they are for | |---|---|---| | constants and pushes | `OP_0`…`OP_16`, the direct pushes | putting data on the stack (signatures, keys, hashes) | | stack | `OP_DUP`, `OP_DROP`, `OP_SWAP` | duplicating and reordering what sits on top | | comparison | `OP_EQUAL`, `OP_EQUALVERIFY` | comparing the two elements on top | | hash | `OP_HASH160`, `OP_SHA256` | computing hashes | | signatures | `OP_CHECKSIG`, `OP_CHECKMULTISIG` (in tapscript: `OP_CHECKSIGADD`) | verifying signatures against keys | | flow | `OP_IF` / `OP_ELSE` / `OP_ENDIF`, `OP_VERIFY`, `OP_RETURN` | branches, halts, outputs declared unspendable | | time | `OP_CHECKLOCKTIMEVERIFY`, `OP_CHECKSEQUENCEVERIFY` | binding the spend to a height or a delay | | arithmetic (reduced) | `OP_ADD`, `OP_SUB`, the numeric comparisons | small sums on small numbers | | disabled (2010) | `OP_CAT`, `OP_MUL`, `OP_LSHIFT`… | removed after the flaws; some are being discussed again today | Best seen on a real lock. This is P2PKH, the lock of addresses starting with `1`, taken from the most famous of payments (the ten thousand pizza bitcoins, 2010), byte by byte:
P2PKH1… · since 2009 25 bytes 1 OP_DUP = 76 76 OP_DUP 1 OP_HASH160 = a9 a9 OP_HASH160 1 push 20 = 14 14 push 20 20 key hash · 20 bytes = 46af3fb481837fadbb421727f9959c2d32a36829 46 … 29 key hash 1 OP_EQUALVERIFY = 88 88 OP_EQUALVERIFY 1 OP_CHECKSIG = ac ac OP_CHECKSIG the 10,000 BTC output of the pizza transaction · tx a1075db5…, block 57043 (2010)
The P2PKH lock byte by byte: the scriptPubKey of output 0 (10,000 BTC) of a real transaction, the 10,000 BTC output of the pizza transaction, block 57043 (2010). Boxes: blue = ops, yellow = data, grey = length; the numbers above the boxes are their byte counts. Verifiable with getrawtransaction a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d.
Each box is a byte, or a group of bytes, with its hexadecimal value inside and the byte count above. Blue boxes are **ops**, the instructions; yellow ones are **data**; grey ones are a special kind of byte, the **push**, worth pausing on because it returns in every lock. A push byte orders nothing: it declares "the next N bytes are data, put them on the stack as they are". The grey `14`, for instance, is the number twenty, and announces that twenty bytes follow, the hash of the key. This is how the script separates data from instructions without ambiguity: a value is never mistaken for a command, because its push always introduces it. Before following an execution, it is worth making clear who brings what, because not everything comes from whoever spends. The node already has the lock. Whoever spends does not send it: it is written on the output of an earlier transaction, normally confirmed some time before, and every node keeps it in the UTXO set, the collection of all coins spendable at that moment. The spending transaction merely points at it, saying which past transaction and which of its outputs. It could not be otherwise: if the lock came from whoever spends, everyone would bring their own. Only one thing arrives from outside, the unlocking data: it travels inside the spending transaction, in the scriptSig, and from SegWit onwards in a separate area of the transaction, the witness. And the message, the text the signature is verified against, does not travel at all. It is the spending transaction reduced to a number by fixed rules, rules that leave the unlocking data out: if they included it, the signature would have to cover itself. Whoever signs computes it before signing, the node recomputes it on its own from what it received, and the two numbers match only if the transaction has stayed the same. Nobody transmits it because nobody needs to receive it: both sides have the transaction. One thing stays outside all this, the private key, which appears neither in the lock, nor in the unlocking data, nor in the message. How much whoever spends has to bring depends on the type of lock: where there is a hash the key must be shown, because the node does not have it; where the key is already there, the signature is enough. Ops do not "fire" on call: the script is walked left to right, one element at a time, and each op acts when its turn comes, on what the previous steps left on the stack. First, though, the unlocking data is stacked: whoever spends puts their signature and their key up front, and only then does the lock run. Unlock first, lock after, on the same stack. In the P2PKH above the order is this: 1. the unlocking data goes on the stack: the signature and the public key; 2. `OP_DUP` duplicates the key, `OP_HASH160` computes its hash; 3. `OP_EQUALVERIFY` compares that hash with the twenty bytes written in the lock: if they do not match, execution stops here and the spend is void; 4. `OP_CHECKSIG` verifies the signature against the key: if it holds, it leaves "true" on the stack and the spend is valid. These are the four ops and the single push that can be read in the strip, executed in that order. Step 4 deserves a closer look, because that is where the mechanism closes. `OP_CHECKSIG` does not compare two values: it rebuilds the text the signature was meant to cover, that is, the transaction reduced to a number by fixed rules, and then verifies that a certain relation holds between that number, the public key and the two numbers of the signature. The relation holds only if the signer possessed the private key, and holds only for that transaction: the same signature, moved onto another one, would not. Which parts of the transaction enter the count is declared by the signature itself, with one byte at its tail. What the check establishes stops there, though: that the signer possessed the key at that moment, and consented to that spend. Not who they were, not whether the key was theirs alone, not whether it had been taken from them. On Bitcoin ownership is defined exactly like this, as possession of the key, and the lock has no way of looking further. Then there is a limit of the same kind: `OP_CHECKSIG` judges the signature it receives, not the way it was produced. That side has conditions of its own too, all on the signer's side: the most delicate one concerns the [**nonce**](/en/signature-nonce/), the number every signature consumes exactly once and that must never repeat. One question about the language remains, and it carries all that follows: if it allows arbitrary combinations, why are the lock types a handful? Because nodes, when deciding whether to relay a transaction, recognize a few fixed shapes, the **standard** scripts: outside those shapes a lock can be valid under consensus rules yet travel poorly on the network. The types in the next table are precisely those shapes, and their chronology is the story of how the list grew longer. Over time *where* the unlocking data lives has changed as well (inside the body of the transaction, then in a section of its own: more under SegWit), but the stack mechanism has stayed the same. ## A handful of types Before the chronology, the overview. This table is for consulting, not studying: it pays to come back to it while reading the sections that follow. | lock | shape (schematic) | address | when the key shows | |---|---|---|---| | **P2PK** | ` OP_CHECKSIG` | none | at once: the key is already on the output | | **P2PKH** | `OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG` | `1…` | at the first spend | | **bare multisig** | `m n OP_CHECKMULTISIG` | none | at once: the keys are on the output | | **P2SH** | `OP_HASH160