Base58 Encoder & Decoder | Verify Bitcoin addresses and Base58Check rolls offline
When you need to wrap a hex public-key hash into a Bitcoin P2PKH address, sanity-check the Base58Check implementation in your own script, or peel apart a Solana key or IPFS CIDv0 to look at the raw bytes — this tool encodes and decodes Bitcoin-style Base58 with five version-byte presets (P2PKH 0x00, P2SH 0x05, WIF 0x80, Testnet P2PKH 0x6f, Testnet P2SH 0xc4) and runs the double-SHA256 checksum verdict in BigInt + Web Crypto without leaving your browser tab.
💡 About this tool
Bitcoin's Base58 alphabet was designed to be readable when written down or typed by hand. Satoshi dropped four characters — 0, capital O, capital I, lowercase l — that visually collide on noisy QR scans and in handwriting, and trimmed out +, /, = so the result is safe inside URLs, command-line arguments, and JSON strings without any extra escaping.
Base58Check adds a one-byte version prefix and a four-byte checksum (the first four bytes of SHA256(SHA256(version || payload))) so the encoder catches one-character typos before they hit your wallet, RPC client, or storage layer. The same envelope shows up across the ecosystem: Bitcoin mainnet and testnet addresses, WIF (Wallet Import Format) private keys, Solana keypair public keys (raw Base58, no checksum), IPFS CIDv0 multihashes (Qm…), and even legacy Flickr photo IDs.
This tool decouples both halves of the workflow. The encoder takes a hex byte string, optionally prepends a version byte, and emits the canonical Base58 / Base58Check string. The decoder takes the string back, reports the version byte separately, dumps the payload as both hex and printable ASCII, and shows whether the checksum agrees with the bytes you pasted. Everything happens with BigInt arithmetic and the built-in crypto.subtle.digest('SHA-256', …) API, so the output matches what python-base58, btcutil/base58, rust-bitcoin, and bitcoinjs-lib would produce.
Privacy: Because WIF (0x80) is one of the presets, you may end up pasting private-key material. Nothing is sent to a server — every byte stays inside the page and is fed straight into the browser's BigInt and Web Crypto stack.
🧐 Frequently Asked Questions
Q. How is Base58 different from Base64?
A. Base64 uses A-Z a-z 0-9 + / =, 64 characters. Base58 strips 0, O, I, l and the punctuation, leaving 58. The encoded form is roughly 4% longer than Base64, but the result is URL-safe, copy-and-paste-safe, and doesn't fall apart when somebody reads it over the phone or scans a faded paper backup.
Q. How is the Base58Check checksum computed? A. Concatenate the version byte with the payload, run SHA-256 on that twice, take the first four bytes of the second hash, and append them to the payload. The decoder repeats the same arithmetic on the version + payload it just extracted and compares the recomputed bytes with the trailing four. A single bit-flip anywhere changes the checksum completely, so most copy-paste typos fail the check.
Q. Can I decode Litecoin, Dogecoin, Solana, or IPFS CIDv0 here?
A. Solana public keys and IPFS CIDv0 are raw Base58 (no Base58Check envelope) — switch to "Raw Base58" mode and the byte payload comes back cleanly. Litecoin (0x30 P2PKH, 0x05/0x32 P2SH) and Dogecoin (0x1e) use Base58Check with different version bytes that aren't in the preset list; the safest workaround is to assemble version + payload + double_sha256(version + payload)[:4] in your own script and paste the hex into the Raw Base58 encoder here for a side-by-side check.
Q. The checksum verdict says "invalid" — what now?
A. Three usual suspects. First, a 0 got swapped for O or I for l somewhere in the string — Base58 doesn't define those characters at all, so the decoder errors out before checksum. Second, an editor or messaging app converted full-width characters or "smart quotes". Third, the input is raw Base58 (Solana, IPFS CIDv0) rather than Base58Check — switch to Raw Base58 mode and it decodes fine.
Q. Why does my decoded WIF payload have 33 bytes instead of 32?
A. Compressed-WIF private keys append a single 0x01 byte after the 32-byte private key to flag "compressed pubkey form". Uncompressed WIF gives you exactly 32 bytes. You can read the format off the decoded hex length directly.
📚 Fun Facts
The Base58 alphabet starts with 1 instead of 0 on purpose. Bitcoin's encoder represents each leading zero byte with a literal 1, which is why mainnet P2PKH addresses (version byte 0x00) start with 1, P2SH addresses (0x05) start with 3, and uncompressed WIF (0x80) starts with 5. Compressed WIF strings start with K or L because the appended 0x01 shifts the numeric range past 5….
Flickr's original Base58 implementation used its own alphabet ordering (123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ), which is why a Flickr photo URL like https://flic.kr/p/2nABcDef won't decode against Bitcoin's alphabet without a manual remap. Solana, Stellar, and IPFS all adopted Bitcoin's ordering, so they share decoders cleanly — IPFS even called this the "btc" alphabet in the original go-ipfs source.