Private key → compressed WIF
Base58Check-encode the payload 0x80 ‖ k ‖ 0x01 and get the 52-character K…/L… Wallet Import Format string that tells a wallet to derive the compressed public key — the modern default, and the format behind every SegWit- and Taproot-capable single-key import.
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
You give it a 256-bit private key and it produces the compressed WIF — the
Wallet Import Format string that starts with K or L, is 52 characters long, and tells
a wallet to derive the compressed public key from that key. WIF is not a new secret and not a new kind
of key: it is your private key, plus two bytes of metadata, plus a checksum, written in Base58.
Every part of that chain is shown separately in the result panel above: the payload, each of its fields, the hash, the checksum, and the final string.
1. What Base58 is, and why the alphabet skips 0 O I l
Base58 is positional notation in base 58 — like decimal or hexadecimal, but with a hand-picked alphabet of 58 characters. Encoding a byte string means treating it as one huge integer and repeatedly dividing by 58, collecting remainders; decoding reverses that. The alphabet is case-sensitive and free of punctuation, so a string can be read aloud, typed from a printed page or embedded in a QR code without quoting or escaping.
| Alphabet segment | Characters | Count | Deliberately absent |
|---|---|---|---|
| Digits | 1 2 3 4 5 6 7 8 9 | 9 | 0 (confused with O) |
| Upper case | A B C D E F G H J K L M N P Q R S T U V W X Y Z | 24 | I (confused with 1 and l), O (confused with 0) |
| Lower case | a b c d e f g h i j k m n o p q r s t u v w x y z | 25 | l (confused with 1 and I) |
| Total | 58 | 9 + 24 + 25 = 58 | |
Those four omissions are the entire point of the alphabet. Bitcoin keys and addresses are transcribed by humans
— off a screen, a paper backup, a metal plate — and the likeliest transcription error is
0↔O or 1↔I↔l. Deleting the ambiguous glyphs
removes a whole class of mistakes instead of merely detecting it later.
- Leading zero bytes become
1. A raw big integer loses leading zeros, so Base58 encodes each leading0x00byte as a literal1(alphabet index 0). That is why every mainnet P2PKH address — version byte0x00— begins with1. - A WIF never starts with
1. Its first byte is0x80, whose high bit is set, so there is no leading zero byte to encode.
2. Why there is a checksum, and exactly how it is computed
Base58 alone has no error detection: change one character and you get a different, perfectly well-formed number — which for a private key means another key, or a string some wallet rejects with a cryptic error. Bitcoin therefore appends four checksum bytes before encoding, a scheme called Base58Check:
SHA-256 is applied twice (the SHA256d used for block hashes and transaction IDs), truncated to 32 bits, and appended to the payload. On import a wallet recomputes it and compares. For the demo key the whole computation is visible:
| Stage | Value |
|---|---|
| Payload (34 bytes) | 800824c314772b2c2859c889471390a36bf66e53a1ca1642f96f0f2c9307a171ca01 |
| SHA256(payload) | b6020359be4735a8dafe0d76b886c0de8a09ea9459aeba16cb3e3b5473b5d0c2 |
| SHA256(SHA256(payload)) | 3a0a0417ffa98881ccdd0c7b283639584e0e909389f6bfbbdbac54547d2b732d |
| Checksum (first 4 bytes) | 3a0a0417 |
| Final 38 bytes fed to Base58 | 800824c314772b2c2859c889471390a36bf66e53a1ca1642f96f0f2c9307a171ca013a0a0417 |
The checksum is only 32 bits, so a random corruption slips through with probability 2−32 ≈ 1 in 4.29 billion — long enough to kill typos, short enough to cost four bytes. Change one character of the demo WIF and this page's decoder answers "WIF checksum is invalid (typo or truncated string)" instead of silently returning a different key.
Base58Check protects you from accidents, not from adversaries. Anyone who learns your private key can compute a valid checksum for any WIF they like — there is no authentication and no key material in those four bytes.
3. The payload: 33 bytes of data, 34 with the flag
WIF is defined as a Base58Check encoding of a payload that begins with a version byte. For a compressed key the payload is 34 bytes long, and each byte has a job:
| Offset (payload) | Length | Field | Demo value | Meaning |
|---|---|---|---|---|
| 0 | 1 byte | Version byte | 80 | Mainnet private key (0x80 = 128) |
| 1 – 32 | 32 bytes | The private key itself | 0824c31477…07a171ca | Big-endian scalar, zero-padded to 32 bytes |
| 33 | 1 byte | Compression flag | 01 | "Derive the compressed public key from this key" |
| 34 – 37 | 4 bytes | Checksum | 3a0a0417 | First 4 bytes of SHA256d(bytes 0–33) |
| 38 bytes | 34 bytes of payload + 4 bytes of checksum → 52 Base58 characters | |||
The version byte identifies the coin and the key type, and it is what makes the resulting string recognisable at a glance:
| Version byte | Network / use | Resulting WIF starts with | Payload length |
|---|---|---|---|
0x80 (128) | Bitcoin mainnet, uncompressed | 5 | 33 bytes |
0x80 (128) | Bitcoin mainnet, compressed | K or L | 34 bytes |
0xef (239) | Bitcoin testnet, uncompressed | 9 | 33 bytes |
0xef (239) | Bitcoin testnet, compressed | c | 34 bytes |
0x00 (0) | Not a WIF — P2PKH address version | 1 (address) | 21 bytes |
0x05 (5) | Not a WIF — P2SH address version | 3 (address) | 21 bytes |
Notice the last two rows: 0x00 and 0x05 are address version bytes, not key version
bytes. Three version-like bytes appear across one derivation chain — 0x04 the SEC1 point tag,
0x80 the WIF version, 0x00 the P2PKH version — and mixing them up is a classic
confusion.
4. Why compressed WIFs are 52 characters and start with K or L
Base58 is a big-integer encoding, so the length of the output is set by the size of the number: each Base58 character carries log258 ≈ 5.858 bits. A 38-byte value is 304 bits, and 304 / 5.858 ≈ 51.9, so at most 52 characters are needed. A 37-byte value is 296 bits and 296 / 5.858 ≈ 50.5, giving at most 51 characters. That single byte — the compression flag — is exactly what moves the WIF from 51 to 52 characters.
The first character is a stronger statement. The first Base58 digit is
floor(value / 5851), and a mainnet compressed WIF always begins with the byte
0x80, so its value lies in [2303, 2303 + 2296). With
5851 ≈ 2298.757 the quotient is always between ≈ 18.93 and ≈ 19.08, which can
only floor to 18 or 19 — the alphabet positions of K and
L. For an uncompressed mainnet WIF the value lies in
[2295, 2295 + 2288) and
5850 ≈ 2292.899, giving a quotient between ≈ 4.29 and ≈ 4.32 that always floors
to 4 — the character 5. The leading character is not a convention; it is forced by
the arithmetic.
| Form | Payload | Total encoded bytes | Base58 characters | First character | Demo value |
|---|---|---|---|---|---|
| Compressed (mainnet) | 34 B | 38 B = 304 bits | 52 | K or L | KwVYL77L…GK5tVqG |
| Uncompressed (mainnet) | 33 B | 37 B = 296 bits | 51 | 5 (always) | 5HssbguBn…aVNekU |
A random sample of 400 freshly generated keys on this server produced 184 WIFs starting with K and
216 starting with L, all 52 characters long; 300 uncompressed WIFs from the same keys were all 51
characters and all began with 5. The K/L split is essentially a coin flip,
because it depends on the high bits of the random key.
5. Why the 0x01 flag lives inside the WIF
When compressed keys were introduced in 2012 (see the uncompressed key page for the history), wallets had a problem: a backup of a private key was a single string, and the wallet had to know which public-key serialization to derive. A separate field would have broken every existing parser, printed paper wallet and QR code. Instead the payload grew by one optional trailing byte:
- The slot was free. The 32-byte key has a fixed length, so an optional byte after it is
unambiguous: a 33-byte payload means "uncompressed", a 34-byte payload ending in
0x01means "compressed". - The flag is covered by the checksum. It sits inside the hashed region, so a corrupted or maliciously flipped flag is caught like any other typo. Stored outside the string it would carry no integrity protection at all.
- The flag is a hint, not key material. It changes no bit of the private key; it only tells the wallet which public-key encoding to hash — and therefore which address to look at.
The same private key has two valid WIF strings: KwVYL77L… (compressed) and
5HssbguBn… (uncompressed) for the demo key. They decode to identical 32-byte keys and different
addresses. Neither is "wrong"; they simply describe different derivations. Back up the one that matches where
your coins actually are.
6. How a wallet uses the flag to decide which address to spend from
That branch is the whole point. The flag does not merely affect how the wallet prints your key; it
changes the 20-byte hash the wallet watches on-chain and the public key it pushes when spending. With the flag it
derives hash160(02/03‖X) and pays to 146ZNjH7…; without it,
hash160(04‖X‖Y) and 16kR3eis…. Both are correct addresses for the same key — just
different ones.
This is the classic failure. Old software either rejects the string — "invalid WIF", "wrong length" — or accepts it and derives the uncompressed address anyway. If your coins are at the compressed address you see a zero balance; if you then send coins to the address it displays, your funds are split across two addresses that two wallets may disagree about. Nothing is cryptographically lost — one key still controls both — but you now need the right tool for each balance. Before trusting an import, check that the address the wallet shows is the address you expected.
7. Worked example — every value computed and verified
All of the following are the real outputs for the sample key in the input box:
| Item | Value |
|---|---|
| Private key k | 0824c314772b2c2859c889471390a36bf66e53a1ca1642f96f0f2c9307a171ca |
Payload 0x80 ‖ k ‖ 0x01 | 800824c314772b2c2859c889471390a36bf66e53a1ca1642f96f0f2c9307a171ca01 (34 bytes) |
| Checksum | 3a0a0417 |
| Compressed WIF | KwVYL77Lcs1ckM39NvGjrtfKhU4KKdR2iB9Wq2FSMN6rbGK5tVqG |
| Length / first character | 52 characters, begins with K |
Payload 0x80 ‖ k | 800824c314772b2c2859c889471390a36bf66e53a1ca1642f96f0f2c9307a171ca (33 bytes) |
| Uncompressed-checksum | b6f3d7f5 |
| Uncompressed WIF (contrast) | 5HssbguBnjbaUVZCsH9YuzUG7T4vYQf51iiodi4izdVy6aVNekU |
| Length / first character | 51 characters, begins with 5 |
| Compressed public key implied | 02ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80 |
| hash160 of it | 21f57b6debcfc5b67182dfb4af1641f0a8189012 |
| P2PKH address implied | 146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT |
| Testnet compressed WIF of the same key | cMrXo27C3vhsunWQmL5sEDAPKhMiz5WinDHywShwrUkrr1RkCJ4i |
Note the checksum difference between the two forms: 3a0a0417 versus b6f3d7f5.
Appending the flag byte changes the hash input, so it changes the checksum and the last four characters of the two
strings are unrelated — a useful sanity check when comparing two WIFs of the same key by eye.
8. Round-trip verification
An encoding that cannot be decoded is worthless, so this page decodes its own output with
Btc::wifDecode() and shows every field it recovers in the result panel: the identical 32-byte key,
the compression flag set, version byte 80, network mainnet, a valid checksum, and the 34-byte payload
that went in. Base58Check is a bijection, so the round trip must return the original bytes. If a tool
decodes your WIF to a different key, the string was mistyped or the tool is broken — there is no third
possibility.
9. Compressed vs uncompressed WIF, side by side
| Compressed WIF | Uncompressed WIF | |
|---|---|---|
| Payload | 0x80 ‖ k ‖ 0x01 (34 B) | 0x80 ‖ k (33 B) |
| Total bytes encoded | 38 B | 37 B |
| String length | 52 characters | 51 characters |
| First character (mainnet) | K or L | 5 |
| First character (testnet) | c | 9 |
| Checksum (demo key) | 3a0a0417 | b6f3d7f5 |
| Public key implied | 33 bytes, 02/03‖X | 65 bytes, 04‖X‖Y |
| Address implied (demo key) | 146ZNjH7…2UqT | 16kR3eis…WG2G |
| Usable for SegWit / Taproot | Yes | No |
| Fee to spend from | About 107-byte scriptSig | About 139-byte scriptSig |
| Typical origin | Every wallet since 2012 | Paper wallets and pre-2012 software |
See private key → uncompressed WIF for the mirror-image page and WIF → private key HEX for the decoder that tells you which form a string you were given actually is.
10. Security notes
- A WIF is the private key in plain text. Base58 is an encoding, not encryption. Anyone who sees the string can spend the coins, irreversibly.
- The checksum detects accidents, not attacks. It says nothing about who created a key, and it stops nobody from recomputing a valid checksum for a key of their own choosing.
- Be careful where you paste it. WIF strings are the standard payload of phishing sites, clipboard malware and chat scams. Type a paper wallet's key into software you own, ideally offline.
- A WIF is a single key, not a wallet. Imported into an HD wallet it becomes a standalone, non-derived account: no seed phrase, no xpub, no change addresses, no SegWit or Taproot addresses. If you sweep it, sweep the whole balance to a key you have actually backed up.
- This page sends your key to the server. The request is a plain HTTP GET, so treat every test here as public: use the demo key or another throwaway key, never one protecting real money.
11. Common mistakes
- "Base58 hides my private key." It does not; it is a lossless transformation any decoder reverses in microseconds.
- Reading the
0x01flag as part of the key. The key is 32 bytes, the flag is metadata. Keeping the flag yields a 33-byte "private key", which is invalid. - Confusing the version bytes.
0x80is a WIF,0x00a P2PKH address,0x04an uncompressed public key tag — same byte position, three unrelated meanings. - Expecting a
5…and aK…WIF of one key to give the same address. They never will — that is the entire purpose of the flag. - Hand-editing the last four characters. Those are the checksum; change anything in the string and they must be recomputed. Typing over them is how people "lose" keys that were fine.
- Treating a WIF as a seed phrase. It encodes one key at one derivation position; it cannot generate a family of addresses and it is not a BIP39 mnemonic.
12. Quick reference
| Item | Value |
|---|---|
| Encoding | Base58Check: payload ‖ first 4 bytes of SHA256d(payload) |
| Compressed payload | 0x80 ‖ k(32 B) ‖ 0x01 |
| Payload / encoded length | 34 B / 38 B |
| Output length | 52 Base58 characters |
| First character (mainnet compressed) | K or L |
| Checksum size / strength | 4 bytes / catches all single-character typos in practice (1 in 232 escapes) |
| Base58 alphabet size | 58 (no 0, O, I, l) |
| Flag meaning | Derive the 33-byte compressed public key |
| Address implied | P2PKH from hash160(02/03‖X) |
| Reversible? | Yes — decoding recovers k exactly |