Private key → P2PKH address (compressed)
The classic 1… address: hash the 33-byte compressed public key into 20 bytes, prepend the mainnet version byte 0x00, append a 4-byte double-SHA256 checksum and Base58-encode the result. Every intermediate value is shown so you can follow the construction byte by byte.
Enter a value above and press Convert. Not sure what to type? Press “Use example” to load the sample from the placeholder.
What this page computes
One 256-bit private key goes in; one classic 1… address comes out. The address is not a second
key and not a hash of the private key — it is a Base58Check encoding of a 20-byte commitment to the
compressed public key:
Every intermediate value is shown in the result panel, because the point of this page is to make each step visible rather than to hide it behind a black box.
1. What "P2PKH" actually means
A Bitcoin output is not an account with a balance. It is an amount plus a small program called the
locking script (scriptPubKey). To spend that output, the next transaction supplies
an unlocking script / witness that makes the program finish with a single TRUE on
the stack. P2PKH stands for pay to public key hash, and its locking script is:
OP_DUP OP_HASH160 <20-byte pubkey hash> OP_EQUALVERIFY OP_CHECKSIG
The order matters: the script first re-derives the hash of the public key that the spender supplied, compares it to the committed hash, and only then verifies the signature. Hashing first is what lets the address stay short and keeps the public key off the chain until the coins move.
The Unix-style shorthand <pubkeyhash> OP_CHECKSIG describes the older
P2PK ("pay to public key") form, whose locking script pushes the whole public key instead of a
hash of it. That form is what Satoshi's first transactions used, and its outputs are bigger:
| P2PK (legacy, 2009) | P2PKH (this page) | |
|---|---|---|
| Locking script | <pubkey> OP_CHECKSIG | OP_DUP OP_HASH160 <hash160> OP_EQUALVERIFY OP_CHECKSIG |
| scriptPubKey size | 35 bytes (compressed) / 67 bytes (uncompressed) | 25 bytes |
| Public key on chain before spending | yes — visible from day one | no — revealed only when spent |
| Typical use today | rare; mostly unmoved 2009–2010 coins | the default single-key format for a decade |
Executing the script, step by step
The spender's unlocking script is <sig> <pubkey>. Here is exactly what the
interpreter does, with the demo key's real values:
| # | Operation | Stack afterwards |
|---|---|---|
| 1 | push signature from scriptSig | [sig] |
| 2 | push compressed pubkey from scriptSig | [sig, 02ff812e…ee80] |
| 3 | OP_DUP — copy the top item | [sig, pub, pub] |
| 4 | OP_HASH160 — hash the copy | [sig, pub, 21f57b6d…9012] |
| 5 | push the hash committed in the script | [sig, pub, 21f57b6d…9012, 21f57b6d…9012] |
| 6 | OP_EQUALVERIFY — compare, drop both, abort if unequal | [sig, pub] |
| 7 | OP_CHECKSIG — verify the signature with the pubkey | [TRUE] |
So the hash is not a convenience: it is the identity check. If the spender hands over a public key
that hashes to something else, OP_EQUALVERIFY fails and the spend is rejected before any signature
math is done.
2. The construction, byte by byte
Base58Check is fed 25 bytes. Nothing else is in there — no chain code, no key index, no checksum of the private key:
| Offset | Length | Field | Demo value |
|---|---|---|---|
| 0 | 1 byte | version byte 0x00 = mainnet P2PKH | 00 |
| 1 – 20 | 20 bytes | hash160 = RIPEMD160(SHA256(compressed pubkey)) | 21f57b6debcfc5b67182dfb4af1641f0a8189012 |
| 21 – 24 | 4 bytes | checksum = first 4 bytes of SHA256(SHA256(bytes 0–20)) | cbd7667e |
| — | 25 bytes total | 200 bits, the entire content of a 1… address | 0021f57b…9012cbd7667e |
25 bytes is 200 bits. Because Base58 carries log₂(58) ≈ 5.858 bits per character, the encoded string is 33 or 34 characters long (200 / 5.858 ≈ 34.1). The demo address is exactly 34 characters.
Why the address starts with "1"
Base58 is a big-integer base conversion, and a pure conversion would erase leading zero bytes. So the
encoding has an extra rule: every leading 0x00 byte in the input becomes a literal
1 character at the front of the output. The version byte of a mainnet P2PKH address
is 0x00, so the first character is always 1. Change the version byte and the
leading character changes with it — that single byte is the whole reason 1…, 3… and
m… look the way they do.
A valid mainnet P2PKH address always starts with 1, but the reverse is not guaranteed: a
decoder must check the version byte, the payload length and the checksum. Never treat a prefix as
validation — the demo testnet address below starts with m for exactly this reason.
3. Why hash160 = RIPEMD160(SHA256(x))
Two different hash functions are applied in sequence, and the reason is defence in depth.
A collision in SHA-256 alone is useless to an attacker, because the 32-byte digest is then fed to a second,
structurally different function: to produce two public keys with the same hash160 you need a
collision in the composition, which means breaking both designs. Hashing twice also shortens the
result to 20 bytes, which makes every address, script and output smaller.
| Function | Output | Birthday collision bound | Preimage bound | Role here |
|---|---|---|---|---|
| SHA-256 | 32 bytes / 256 bits | ≈ 2128 | ≈ 2256 | full-strength commitment to the public key |
| RIPEMD-160 | 20 bytes / 160 bits | ≈ 280 | ≈ 2160 | shortens the commitment |
| hash160 = RIPEMD160∘SHA256 | 20 bytes / 160 bits | ≈ 280 | ≈ 2160 | what the address commits to |
The relevant threat for a specific address is a second preimage, not a free collision: the attacker must find a public key hashing to your 160-bit value, which costs about 2160 work. An 80-bit collision bound only matters for generating two colliding keys of the attacker's own choosing, so 20 bytes was judged an acceptable trade for smaller scripts — and it is still unbroken today.
4. What the 4-byte checksum protects against
The checksum is SHA256(SHA256(payload))[0..3] — 32 bits appended to the payload before Base58
encoding. Its whole job is to catch accidental transcription errors: a mistyped character
changes the decoded integer, and the probability that a random corruption still matches those 32 bits is
1 in 232 ≈ 1 in 4.29 billion. That is why stealing a single character from an address makes almost
every wallet reject it loudly.
The checksum is unkeyed and public: anyone can compute a correct one for any payload they like, including a payload that pays them. It protects you from typos and from truncation, not from a malicious address substituted in an email, a clipboard or a compromised website. Always verify at least the first and last few characters on the device that holds the key.
5. Mainnet vs testnet: one byte changes everything
The version byte is the only difference between a mainnet and a testnet P2PKH address for the same hash160. Same 20 bytes, different first byte, completely different strings:
| Network | P2PKH version | P2PKH prefix | P2SH version | P2SH prefix | WIF version | Bech32 prefix |
|---|---|---|---|---|---|---|
| Mainnet | 0x00 | 1… | 0x05 | 3… | 0x80 | bc1 |
| Testnet / signet / regtest* | 0x6F | m… / n… | 0xC4 | 2… | 0xEF | tb1 |
* The test networks share the Base58 version bytes shown here; only the bech32 human-readable part differs
(bcrt1 on regtest). For the demo key's hash160 the mainnet address is
146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT and the testnet one is
micWfnN6LUy38jVRPD2Mw7YMa873zjixGw — the same 20-byte commitment, pointing at different chains.
Both strings decode to the same hash160, but the version byte is part of the output script on the receiving
chain. Paying mainnet coins to a tb1… or m… address is a transaction to an address
whose key you control on the other chain — on mainnet the coins are simply lost. Copy-paste errors
like this are irreversible; there is no operator to call.
6. Worked example with the demo key
These are the exact values this page computes for
0824c314…171ca, and the result panel recomputes them live:
| Step | Value |
|---|---|
| Private key k | 0824c314772b2c2859c889471390a36bf66e53a1ca1642f96f0f2c9307a171ca |
| Compressed public key (33 B) | 02ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80 |
| SHA-256 of that (32 B) | 067eb00a0b9864633b020eef374476142daba913c5481ad6a4741cc8ab702617 |
| hash160 = RIPEMD-160 of that (20 B) | 21f57b6debcfc5b67182dfb4af1641f0a8189012 |
Payload = 00 ‖ hash160 (21 B) | 0021f57b6debcfc5b67182dfb4af1641f0a8189012 |
| Checksum (4 B) | cbd7667e |
| Encoded 25 bytes | 0021f57b6debcfc5b67182dfb4af1641f0a8189012cbd7667e |
| P2PKH address | 146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT (34 characters) |
| Matching scriptPubKey (25 B) | 76a91421f57b6debcfc5b67182dfb4af1641f0a818901288ac |
Reading the scriptPubKey: 76 = OP_DUP, a9 = OP_HASH160,
14 = "push the next 20 bytes", then the hash, 88 = OP_EQUALVERIFY,
ac = OP_CHECKSIG. Five opcodes and one constant — 25 bytes that define who may spend.
7. Why an address is not a public key
- It is a one-way commitment. The public key is not stored in the address; only its 160-bit hash is. Recovering the key from the address means inverting SHA-256 and RIPEMD-160, for which no method better than brute force is known.
- You cannot verify a signature from an address alone. ECDSA verification needs the public key, which is why the spender must reveal it inside the unlocking script.
- The address does not say how the key was serialized. Compressed and uncompressed keys
both produce a perfectly ordinary-looking
1…address; the version byte and length are identical. You cannot tell from an address whether the coins are at the compressed or the uncompressed variant of that key. - It is not a private key either. Publishing an address reveals nothing that allows spending, which is exactly why it is safe to hand out.
Because the public key stays hidden until the coins move, a P2PKH address that has never spent is
protected by two independent problems: the hash preimage (2160) and, for anyone who
does see the key later, the elliptic-curve discrete log. Addresses that have already spent expose their key
and lose the first layer — a real consideration when thinking about future quantum attackers.
8. Address reuse is a privacy bug, not a consensus bug
The blockchain is a public, permanent ledger, so an address is not an account you can hide behind — it is a permanent label. Every payment to the same address is linked together for anyone to see, together with the amounts and the timing. Two consequences deserve emphasis:
- Clustering. Reusing one address for salary, exchange withdrawals and donations lets an observer build a map of your income, your counterparties and your spending without ever breaking any cryptography.
- Key exposure. The first time an address spends, its public key becomes public for that output, permanently. Fresh addresses keep the preimage layer intact for all funds that have not moved.
The standard remedy is a hierarchical deterministic wallet (BIP32/BIP44): it derives a fresh address for every payment from the same seed, and sends change to a new address too. Reusing an address costs nothing in fees and is still perfectly valid on-chain — which is precisely why so much software does it anyway.
9. Where this fits in the derivation chain
- Before this page: private key → compressed public key produces the 33 bytes that get hashed here.
- Sibling: the same address built from the uncompressed 65-byte key — a different address for the same secret.
- Sibling: the nested SegWit
3…address and the native SegWitbc1q…address, which reuse the identicalhash160. - Reverse direction: a public key → hash160 → addresses needs no private key at all.
10. Security notes
This tool computes everything in PHP on the server that serves it, and nothing is logged or sent anywhere — but that guarantee is only as good as the operator. Anyone who sees your key, even for a second, in a log, a proxy, a screenshot or a browser history, can spend every coin at every address derived from it. For real funds, do this offline with software you built yourself, or use a hardware wallet.
- An address reveals nothing about the key, so it is safe to share; the key and the WIF are not.
- Verify addresses character by character on the signing device. The 4-byte checksum catches typos, not deliberate substitution.
- Send a small test amount first when a new address is involved, and wait for confirmations before the rest.
11. Common mistakes
- Hashing the uncompressed key by accident. Importing a
K…/L…WIF into a wallet that hashes the 65-byte form (or the reverse) shows a zero balance for coins that are perfectly safe at the other address. - Believing the address can be reversed. No amount of computing power turns
146ZNjH7…back into a public key or a private key; only a full search of the hash's preimage would, and that is infeasible. - Treating a prefix as validation.
1at the start does not prove the address is correct, on the right network, or even P2PKH — decode it. - Hand-editing a rejected address. If a wallet says "invalid checksum", the address is wrong; guessing the correction is how coins are destroyed.
- Confusing mainnet with testnet. Both look plausible; the version byte decides which chain the coins land on.
12. Quick reference
| Item | Value |
|---|---|
| Formula | Base58Check(0x00 ‖ hash160(compressed pubkey)) |
| Hash input | 33-byte compressed public key (66 hex digits) |
| Hash function | hash160 = RIPEMD160(SHA256(x)), 20 bytes |
| Version byte | 0x00 mainnet, 0x6F testnet |
| Encoded payload | 25 bytes = 1 version + 20 hash + 4 checksum |
| Checksum | first 4 bytes of SHA256(SHA256(payload)), 32 bits |
| Address length | 33 or 34 Base58 characters |
| Locking script size | 25 bytes |
| Demo address | 146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT |
| Reversible? | No — one-way hash commitment |