Standard Scripts & Address Types (P2PK → P2TR)
People say “send Bitcoin to this address,” but Bitcoin has no concept of an address at the protocol level — only outputs with locking scripts. An address is a user-facing shorthand: a compact, error-checked encoding that tells a sender’s wallet which kind of lock to build and what to put in it. This page traces the standard lock shapes from the original P2PK to modern Taproot, and shows what each address string actually commits to.
An address is a commitment to a locking script
Section titled “An address is a commitment to a locking script”When you hand someone an address, you are really saying: “build an output whose scriptPubKey is of
type X, committing to my key/script Y.” The wallet decodes the address, recognizes the type from its
prefix and encoding, and constructs the matching lock. The address never travels onto the chain — only
the scriptPubKey it described does.
address (you give this out) │ decode + error-check ▼ "type + committed key/script hash" │ wallet builds ▼ scriptPubKey (this is what's stored on-chain)Two encodings dominate. Base58Check (legacy, leading 1 or 3) and Bech32 / Bech32m
(SegWit and Taproot, bc1...). The encoding details — checksums, character sets, why typos are
caught — live in addresses & encoding.
The evolution of standard scripts
Section titled “The evolution of standard scripts”Each new type was introduced to fix a shortcoming of the last: smaller, safer, more private, or more flexible.
P2PK — Pay to Public Key
Section titled “P2PK — Pay to Public Key”The original. The lock is simply <pubKey> OP_CHECKSIG — “sign for this exact public key.” It has no
short address form (the raw key is large) and exposes the public key on-chain immediately. Used in the
earliest blocks; essentially obsolete today.
P2PKH — Pay to Public-Key-Hash
Section titled “P2PKH — Pay to Public-Key-Hash”The classic 1... address. The lock commits to the hash of the public key:
OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG. Smaller than P2PK and the raw key stays
hidden until spending. This is the script we stepped through.
P2SH — Pay to Script-Hash
Section titled “P2SH — Pay to Script-Hash”The 3... address. Instead of committing to a key, the lock commits to the hash of an entire
redeem script: OP_HASH160 <scriptHash> OP_EQUAL. The spender later reveals the full script and
satisfies it. This is what made complex locks (multisig, escrow) usable as ordinary-looking addresses
— the sender doesn’t need to know or pay for the complicated script; the recipient reveals it only
when spending.
P2WPKH — Pay to Witness-Public-Key-Hash (SegWit v0)
Section titled “P2WPKH — Pay to Witness-Public-Key-Hash (SegWit v0)”The bc1q... address. Functionally P2PKH, but the unlocking data (signature + key) moves into the
witness rather than scriptSig. This fixed transaction
malleability and made the signature cheaper, because witness
bytes are discounted when computing transaction weight. (Its sibling P2WSH is the SegWit version
of P2SH for arbitrary scripts.)
P2TR — Pay to Taproot
Section titled “P2TR — Pay to Taproot”The bc1p... address. Taproot commits to either a single (Schnorr) public key or a hidden tree of
alternative spending scripts — and lets the common “just one key” case look identical to any
other Taproot spend on-chain, revealing the extra scripts only if they’re used. The result is better
privacy and cheaper, more flexible contracts. The cryptography (Schnorr signatures, key aggregation)
is covered in Taproot, Schnorr & MuSig.
Comparison table
Section titled “Comparison table”| Type | Address prefix | Encoding | Commits to | Introduced for |
|---|---|---|---|---|
| P2PK | (no address) | — | a raw public key | the original coinbase payouts |
| P2PKH | 1... | Base58Check | hash of a public key | smaller addresses, hide key until spend |
| P2SH | 3... | Base58Check | hash of a redeem script | arbitrary locks as simple addresses |
| P2WPKH | bc1q... | Bech32 | hash of a public key (in witness) | malleability fix, cheaper signatures |
| P2WSH | bc1q... (longer) | Bech32 | hash of a witness script | SegWit version of P2SH |
| P2TR | bc1p... | Bech32m | a Schnorr key or script tree | privacy, flexibility, cheaper contracts |
Under the hood — what the bytes inside an address actually are
Section titled “Under the hood — what the bytes inside an address actually are”An address string is a thin wrapper around a payload plus a checksum. The two encoding families lay those bytes out differently:
Base58Check (legacy — "1..." and "3...") [version byte] + [20-byte hash] + [4-byte checksum] then Base58 version 0x00 → P2PKH (leading "1") version 0x05 → P2SH (leading "3") checksum = first 4 bytes of double-SHA-256 of (version + hash)
Bech32 / Bech32m (SegWit & Taproot — "bc1...") HRP "bc" + "1" + [witness version] + [program] + [6-char checksum] witness version 0, 20-byte program → P2WPKH (Bech32, "bc1q...") witness version 0, 32-byte program → P2WSH (Bech32, "bc1q...") witness version 1, 32-byte program → P2TR (Bech32m, "bc1p...")Two things fall out of this. First, the human-visible prefix isn’t decorative — it’s a direct readout
of the version byte (or the witness version), which is why 1, 3, bc1q and bc1p map cleanly
onto distinct script types. Second, Taproot uses Bech32m, a tweaked checksum, because the original
Bech32 had a subtle weakness when an address’s length changed; Bech32m closes it, so a mistyped or
mis-padded address still fails the check before any coins move.
The thread
Section titled “The thread”How do address types help untrusting strangers agree on one ledger? An address compresses “here is
exactly the lock to put on my coins, with a checksum so you can’t get it wrong” into a string a
stranger can paste. The sender doesn’t need to trust the recipient about how the funds will be
guarded — the address itself, once decoded, fully and verifiably specifies the on-chain
scriptPubKey that every node will independently enforce. And because each new type is a
backward-compatible soft fork, the network can adopt better locks over time while every node — old or
new — still agrees on one history. The address is the handshake; the script is the contract; consensus
is the enforcement.
The architect’s lens
Section titled “The architect’s lens”Step back from the prefixes and ask the five questions an architect asks of any naming scheme:
- Why does it exist? To give a sender a compact, error-checked string that fully specifies which kind of locking script to build and what key/script hash to commit to — without the recipient ever publishing the raw script.
- What problem does it solve? Safely communicating a spending condition between strangers: the
Bech32/Bech32m checksum rejects a mistyped character before funds move, and the prefix (
1,3,bc1q,bc1p) tells the wallet exactly whichscriptPubKeyshape every node will enforce. - What are the trade-offs? A proliferation of incompatible types — six and counting — each a real consensus distinction, not cosmetic; send to a type a chain doesn’t recognize and the coins can be unspendable. Newer encodings (Bech32m for Taproot) exist precisely to patch subtle flaws in the old.
- When is it the wrong design? When you’d rather expose the script directly (P2PK locks to a raw key with no address at all), or on a chain using the account model, where a single long-lived account identifier replaces the per-output, fresh-lock convention.
- What breaks if I remove it? Senders would hand-build raw
scriptPubKeys with no checksum and no type signal — a single typo would burn coins silently, and the soft-fork upgrade path that lets old and new nodes share one ledger would lose its clean version-byte handshake.
Check your understanding
Section titled “Check your understanding”- Why does Bitcoin have “no addresses” at the protocol level, and what does an address actually encode?
- What does P2SH commit to that P2PKH does not, and why was that useful?
- What changed between P2PKH and P2WPKH, and which two problems did the change address?
- Match each prefix —
1...,3...,bc1q...,bc1p...— to its script type. - How do soft forks let Bitcoin introduce new address types without splitting the ledger?
Show answers
- At the protocol level there are only outputs with locking scripts (
scriptPubKeys) — the address never goes on-chain. An address is a user-facing shorthand: a compact, error-checked encoding that tells the sender’s wallet which type of lock to build and what key/script hash to commit to. - P2PKH commits to the hash of a public key (
OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG); P2SH commits to the hash of an entire redeem script (OP_HASH160 <scriptHash> OP_EQUAL). That let complex locks like multisig or escrow appear as ordinary3...addresses — the sender needn’t know or pay for the script; the recipient reveals it only when spending. - P2WPKH is functionally P2PKH, but the unlocking data (signature + key) moves out of
scriptSiginto the witness. That fixed transaction malleability and made signatures cheaper, since witness bytes are discounted when computing transaction weight. 1...→ P2PKH (Base58Check);3...→ P2SH (Base58Check);bc1q...→ P2WPKH / P2WSH SegWit v0 (Bech32);bc1p...→ P2TR Taproot (Bech32m).- Each new type ships as a soft fork designed so old nodes still see the spends as valid (often as “anyone-can-spend” outputs they choose not to enforce) while upgraded nodes enforce the stricter real rules. That backward-compatible path is how the network adopts better locks over time while every node — old or new — still agrees on one history; see soft forks & anyone-can-spend.