How Bitcoin Addresses Work: From P2PKH to Bech32m
A comprehensive technical guide to Bitcoin address types — P2PKH (1...), P2SH (3...), P2WPKH (bc1q...), P2TR (bc1p...). Covers Base58Check vs Bech32/Bech32m encoding, checksum mechanisms, key derivation, and why Bech32m is superior.
A Bitcoin address is not an account. It is not stored on the blockchain. It is not registered anywhere. A Bitcoin address is a compact, human-readable encoding of a locking script — the program that specifies the conditions under which bitcoin can be spent. When you “send bitcoin to an address,” you are creating a transaction output locked by the script that the address encodes. Understanding addresses means understanding how Bitcoin translates between the cryptographic primitives that secure your funds and the strings of characters you copy and paste.
Bitcoin has gone through four major address formats over its history, each representing an evolution in encoding efficiency, error detection, and the underlying script capabilities. The progression from P2PKH to P2TR is not merely cosmetic — it reflects fundamental improvements in Bitcoin’s security, privacy, and scalability.
The Derivation Path: From Private Key to Address
Before examining specific address formats, it is essential to understand the derivation chain that produces an address from a private key. This process is a one-way function at every step — you can derive forward but never backward.
Step 1: Private Key Generation
A Bitcoin private key is a 256-bit (32-byte) random number, chosen from the range 1 to n-1, where n is the order of the secp256k1 elliptic curve (approximately 1.158 x 10^77). The security of your bitcoin depends entirely on the randomness of this number. If it can be guessed, predicted, or computed, your bitcoin can be stolen.
In practice, this is a number between 1 and approximately 115,792,089,237,316,195,423,570,985,008,687,907,852,837,564,279,074,904,382,605,163,141,518,161,494,337. The number of possible private keys exceeds the estimated number of atoms in the observable universe (approximately 10^80).
A private key in hexadecimal looks like:
e9873d79c6d87dc0fb6a5778633389f4453213303da61f20bd67fc233aa33262
Step 2: Public Key Derivation (Elliptic Curve Multiplication)
The public key is derived from the private key using elliptic curve point multiplication on the secp256k1 curve. Given a private key k and the curve’s generator point G, the public key K is:
K = k * G
This is a one-way operation — computing K from k and G is straightforward (a few milliseconds), but computing k from K and G is computationally infeasible (it would take longer than the age of the universe with current technology).
The result is a point on the elliptic curve with x and y coordinates, each 256 bits. The uncompressed public key is 65 bytes: a 0x04 prefix byte followed by 32 bytes for x and 32 bytes for y. The compressed public key is 33 bytes: a 0x02 or 0x03 prefix (indicating whether y is even or odd) followed by 32 bytes for x. Since the y coordinate can be computed from x (there are only two possible y values for each x on the curve), the compressed format is sufficient and is now standard.
Compressed public key example:
0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352
Step 3: Hashing (for Legacy and SegWit v0 addresses)
For P2PKH, P2SH, and P2WPKH addresses, the public key is hashed to produce a shorter, fixed-length identifier:
HASH160(publicKey) = RIPEMD-160(SHA-256(publicKey))
This produces a 20-byte (160-bit) hash. The double hashing serves two purposes:
- Size reduction: 33 bytes (compressed public key) → 20 bytes (hash)
- Quantum resistance layer: Even if an attacker could reverse the elliptic curve (extracting the private key from the public key), they would first need to find the public key from its hash — which requires breaking RIPEMD-160. This provides defense-in-depth against future quantum computers, but only for addresses whose public key has never been revealed (i.e., addresses that have only received, never spent).
Step 4: Encoding
The raw hash is then encoded into a human-readable string using one of two encoding schemes: Base58Check (legacy) or Bech32/Bech32m (modern).
Address Type 1: P2PKH — Pay-to-Public-Key-Hash
Format: Starts with 1
Example: 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa (Satoshi’s genesis block address)
Encoding: Base58Check
Active since: Genesis block (January 3, 2009)
P2PKH was the original Bitcoin address format. When you send bitcoin to a P2PKH address, you create an output with the following locking script:
OP_DUP OP_HASH160 <20-byte pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
To spend this output, the owner must provide their public key and a valid ECDSA signature in the unlocking script.
Base58Check Encoding
P2PKH addresses use Base58Check encoding, a format designed by Satoshi Nakamoto specifically for Bitcoin.
Base58 is a subset of Base64 that removes visually ambiguous characters:
- Removes
0(zero) andO(uppercase O) — they look alike - Removes
I(uppercase I) andl(lowercase L) — they look alike - Removes
+and/— they cause issues in URLs and filenames
The resulting character set is: 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
Base58Check adds a checksum to Base58:
- Start with the version byte + payload:
0x00+<20-byte pubKeyHash> - Compute the checksum:
SHA-256(SHA-256(version + payload)), take the first 4 bytes - Concatenate:
version + payload + checksum - Encode the result in Base58
The version byte 0x00 is what makes P2PKH addresses start with 1 after Base58 encoding.
Encoding example:
Public Key (compressed):
0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352
SHA-256 of public key:
0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98
RIPEMD-160 of above:
f54a5851e9372b87810a8e60cdd2e7cfd80b6e31
Add version byte (0x00):
00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31
Double SHA-256 for checksum:
c7f18fe8... (take first 4 bytes: c7f18fe8)
Concatenate:
00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31c7f18fe8
Base58 encode:
1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs
Base58Check Limitations
While Base58Check was a reasonable design for 2009, it has significant limitations:
Case sensitivity. Base58 uses both uppercase and lowercase letters, making addresses case-sensitive. Mistyping a single character’s case can change the address entirely.
Error detection weakness. The 4-byte checksum detects errors with high probability but is not optimized for specific error patterns. It cannot correct errors, only detect them.
Inefficient QR encoding. QR codes have an alphanumeric mode that is significantly more compact than binary mode, but it only supports uppercase characters. Since Base58 includes lowercase letters, Base58Check addresses must use QR binary mode, producing larger QR codes.
No error localization. When a checksum fails, you know the address is wrong, but you do not know where the error is.
Address Type 2: P2SH — Pay-to-Script-Hash
Format: Starts with 3
Example: 3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy
Encoding: Base58Check
Active since: BIP-16 (2012)
P2SH addresses encode the hash of an arbitrary script rather than the hash of a public key. The sender does not need to know the script — they only need the 20-byte hash. The actual script is revealed when the output is spent.
The encoding process is identical to P2PKH, except the version byte is 0x05 (which produces addresses starting with 3 after Base58 encoding):
Base58Check(0x05 + HASH160(redeemScript) + checksum)
P2SH is commonly used for:
- Multisig wallets — the redeem script contains an OP_CHECKMULTISIG
- Wrapped SegWit (P2SH-P2WPKH) — a P2SH script that wraps a SegWit witness program, providing SegWit benefits with backward-compatible addresses (still starts with
3)
The P2SH-P2WPKH Transitional Format
During the SegWit transition, many wallets used P2SH-P2WPKH: a P2SH address whose redeem script is a SegWit v0 witness program. This allowed SegWit transactions to be sent from wallets that did not yet understand native SegWit addresses (bc1q…), since any wallet that supported P2SH could send to a 3... address.
The trade-off was efficiency — P2SH-P2WPKH transactions are slightly larger than native P2WPKH transactions because they include the P2SH wrapper. This format is now largely unnecessary as native SegWit support is nearly universal.
Address Type 3: P2WPKH — Pay-to-Witness-Public-Key-Hash (SegWit v0)
Format: Starts with bc1q
Example: bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq
Encoding: Bech32
Active since: BIP-141/143/173 (2017)
P2WPKH is the native SegWit version 0 address format. It uses an entirely new encoding scheme — Bech32 — designed to address all the limitations of Base58Check.
The locking script is:
OP_0 <20-byte pubKeyHash>
Where OP_0 indicates SegWit version 0 and the 20-byte hash is the same HASH160 of the public key used in P2PKH.
Bech32 Encoding
Bech32 (BIP-173), designed by Pieter Wuille and Greg Maxwell, is a comprehensive improvement over Base58Check.
Structure of a Bech32 address:
bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq
│ │ │ │
│ │ └──────── data ────────────────────────┘
│ └── separator
└── human-readable part (HRP)
Components:
- Human-readable part (HRP):
bcfor mainnet,tbfor testnet - Separator:
1(the digit one, always) - Data: The witness version and witness program, encoded in base-32, plus a 6-character checksum
Character set: Bech32 uses only 32 characters: qpzry9x8gf2tvdw0s3jn54khce6mua7l. All lowercase (or all uppercase — the encoding is case-insensitive). This eliminates the case-sensitivity problem of Base58Check.
BCH checksum: Bech32 uses a BCH (Bose-Chaudhuri-Hocquenghem) code for error detection, which is fundamentally superior to Base58Check’s double-SHA-256 checksum:
- Guaranteed detection of any error affecting up to 4 characters
- Detection of most errors affecting more than 4 characters
- Error localization — the checksum can identify where the error is, not just that an error exists
- The BCH code is specifically optimized for the 32-character alphabet and typical address lengths
QR code efficiency: Because Bech32 uses only lowercase alphanumeric characters (plus the digit separators), QR codes can use the more efficient alphanumeric mode when the address is uppercased. This produces QR codes that are approximately 30-40% smaller than Base58Check addresses, improving scannability on small screens and low-resolution displays.
Bech32 encoding example:
Witness version: 0 (for P2WPKH)
Witness program: f54a5851e9372b87810a8e60cdd2e7cfd80b6e31 (20-byte pubKeyHash)
Convert to base-32:
[0, 14, 20, 20, 22, ...] (each value 0-31)
Compute BCH checksum:
[encoded data] + [6-character BCH checksum]
Assemble:
bc1q (HRP + separator + version) + [base-32 encoded data] + [checksum]
Result:
bc1q74f9cwrgjujs7pq4f3vxdchnl874qmvxq00e5l
Bech32’s One Weakness
Bech32 has a known weakness: inserting or deleting a q character at the end of the address (just before the checksum) can sometimes produce a valid checksum. This is a consequence of the mathematical properties of the specific BCH code used. For SegWit version 0 addresses, this is mitigated by the fixed length requirement (P2WPKH is always exactly 42 characters, P2WSH is always exactly 62 characters). But for future SegWit versions with potentially variable-length programs, this weakness could be dangerous.
This weakness led directly to the development of Bech32m.
Address Type 4: P2TR — Pay-to-Taproot (SegWit v1)
Format: Starts with bc1p
Example: bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3s7a
Encoding: Bech32m
Active since: BIP-341/350 (November 2021)
P2TR addresses represent SegWit version 1 outputs using the Taproot upgrade. The locking script is:
OP_1 <32-byte tweaked public key>
Note two differences from P2WPKH:
- The version byte is
OP_1(notOP_0) - The witness program is a 32-byte public key (not a 20-byte hash)
Why a Raw Public Key Instead of a Hash?
P2TR uses the raw 32-byte x-coordinate of the public key instead of a 20-byte hash. This design choice has important implications:
Schnorr signature verification requires the public key. Unlike ECDSA (where the public key can be recovered from the signature), Schnorr verification requires the public key as an explicit input. Since the spender must reveal the public key anyway, hashing it in the address provides no additional security — the quantum resistance benefit of hashing disappears once the key is exposed during spending.
Space efficiency. With the hash approach, the spender must provide both the hash (in the output) and the public key (in the witness). With the raw key approach, only the key appears. For key-path spends, this is more efficient.
Simplicity. The locking script is just OP_1 <key> — two elements. No hashing opcodes, no DUP, no EQUALVERIFY. This is the simplest locking script in Bitcoin’s history.
Bech32m Encoding
Bech32m (BIP-350) is a minimal modification to Bech32 that fixes the insertion/deletion weakness. The only difference is a single constant in the checksum computation:
Bech32 checksum constant: 1
Bech32m checksum constant: 0x2bc830a3
This single change ensures that:
- Inserting or deleting characters near the end of the address reliably invalidates the checksum
- All the other desirable properties of Bech32 (error detection, localization, QR efficiency, case insensitivity) are preserved
Compatibility rules:
- SegWit version 0 (P2WPKH, P2WSH) uses Bech32 — addresses start with
bc1q - SegWit version 1+ (P2TR and future versions) uses Bech32m — P2TR addresses start with
bc1p
The q vs p character after bc1 indicates the witness version (0 = q, 1 = p) and implicitly tells you which checksum algorithm was used.
Why Bech32m Is Superior
Comparing all encoding formats:
| Property | Base58Check | Bech32 | Bech32m |
|---|---|---|---|
| Case sensitive | Yes | No | No |
| Error detection guarantee | Probabilistic (4-byte hash) | Up to 4 errors guaranteed | Up to 4 errors guaranteed |
| Error localization | No | Yes | Yes |
| QR code efficiency | Poor (binary mode) | Excellent (alphanumeric) | Excellent (alphanumeric) |
| Insertion/deletion detection | Yes | Weak at end | Yes |
| Used by | P2PKH (1…), P2SH (3…) | P2WPKH (bc1q…) | P2TR (bc1p…) |
Address Prefixes by Network
| Network | P2PKH | P2SH | P2WPKH | P2TR |
|---|---|---|---|---|
| Mainnet | 1... | 3... | bc1q... | bc1p... |
| Testnet | m... or n... | 2... | tb1q... | tb1p... |
| Signet | m... or n... | 2... | tb1q... | tb1p... |
| Regtest | m... or n... | 2... | bcrt1q... | bcrt1p... |
The version bytes that produce these prefixes:
| Address Type | Version Byte | Resulting Prefix |
|---|---|---|
| P2PKH mainnet | 0x00 | 1 |
| P2PKH testnet | 0x6f | m or n |
| P2SH mainnet | 0x05 | 3 |
| P2SH testnet | 0xc4 | 2 |
For Bech32/Bech32m, the HRP determines the prefix:
- Mainnet:
bc - Testnet/Signet:
tb - Regtest:
bcrt
Practical Encoding Example: Same Key, Four Addresses
Let us derive all four address types from the same private key to illustrate the differences.
Private key (hex):
e9873d79c6d87dc0fb6a5778633389f4453213303da61f20bd67fc233aa33262
Compressed public key:
0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352
HASH160 of public key:
f54a5851e9372b87810a8e60cdd2e7cfd80b6e31
P2PKH address:
Base58Check(0x00 + f54a5851e9372b87810a8e60cdd2e7cfd80b6e31 + checksum)
= 1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs
P2SH-P2WPKH address:
Redeem script: OP_0 <f54a5851e9372b87810a8e60cdd2e7cfd80b6e31>
= 0014f54a5851e9372b87810a8e60cdd2e7cfd80b6e31
HASH160 of redeem script: [20-byte hash of the above]
Base58Check(0x05 + HASH160(redeemScript) + checksum)
= 3... address
P2WPKH address (native SegWit v0):
Bech32(hrp="bc", version=0, program=f54a5851e9372b87810a8e60cdd2e7cfd80b6e31)
= bc1q74f9cwrgjujs7pq4f3vxdchnl874qmvxq00e5l
P2TR address (Taproot):
The public key is "tweaked" with the Taproot tweak:
tweaked_pubkey = pubkey + hash(pubkey) * G
[32-byte x-coordinate of tweaked key]
Bech32m(hrp="bc", version=1, program=[32-byte tweaked pubkey x-coordinate])
= bc1p... address
Note that the P2TR derivation involves an additional step: the public key is “tweaked” by adding a commitment point. This tweak enables the Taproot mechanism where the key can optionally commit to a tree of scripts.
Which Address Type Should You Use?
Use P2TR (bc1p…) whenever possible. It provides:
- The best privacy (all Taproot outputs look identical regardless of the underlying script complexity)
- The lowest transaction fees (smallest witness data for key-path spends)
- The most advanced script capabilities (Schnorr signatures, MAST, Tapscript)
- The best error detection (Bech32m encoding)
Use P2WPKH (bc1q…) as a fallback. If a service does not support P2TR, P2WPKH is the next best option. It has lower fees than legacy addresses and uses Bech32 encoding.
Avoid P2PKH (1…) and P2SH (3…) for new usage. These legacy formats have higher transaction fees, larger transaction sizes, and inferior error detection. The only reason to use them is if you are interacting with very old software that does not support SegWit.
As of 2026, the vast majority of Bitcoin wallets and services support at least P2WPKH, and P2TR support is increasingly universal. The Bitcoin network is steadily moving toward Bech32m as the standard address encoding.
For related topics, see our guides on Bitcoin wallet addresses, SegWit, and Taproot.