3.1 KiB
Base58 encoding (Bitcoin alphabet)
(no submodules)
Purpose
Encodes and decodes byte buffers using the Bitcoin Base58 alphabet, which omits the four visually ambiguous characters 0, O, I, and l. Base58 is the encoding of choice for address formats where a human will copy the string by eye (Bitcoin addresses, Solana public keys, some Ethereum vanity formats) and where the absence of punctuation lets the value travel through URLs, QR codes, and plain text without escaping. Leading zero bytes are preserved as the '1' prefix character, matching the behaviour of Bitcoin Base58Check address payloads.
Features
- Bitcoin alphabet:
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz. BigInt-based conversion — no floating point, no length limit beyond JS heap size.- Preserves leading-zero bytes as
'1'prefix characters. - Stable error code
CRYPTO.UTILS.ENCODING.INVALID_INPUTon decode failure.
Usage: Basic Example
import { fromBase58, toBase58 } from "@suaveplan/crypto-utils/encoding";
const addr = toBase58(new Uint8Array([0x00, 0xeb, 0x15, 0x23])); // "1NS..."-style prefix
const back = fromBase58(addr);
Usage: Advanced Example
import { fromBase58, toBase58 } from "@suaveplan/crypto-utils/encoding";
import { CryptoUtilsError } from "@suaveplan/crypto-utils/errors";
function verifyAddressPayload(address: string, expectedLeadingZeros: number): Uint8Array {
let bytes: Uint8Array;
try {
bytes = fromBase58(address);
} catch (err) {
if (err instanceof CryptoUtilsError) {
throw new Error(`Not a Base58 address: ${address}`);
}
throw err;
}
let zeros = 0;
while (zeros < bytes.length && bytes[zeros] === 0) zeros++;
if (zeros !== expectedLeadingZeros) {
throw new Error(`Expected ${expectedLeadingZeros} leading zero bytes, got ${zeros}`);
}
return bytes;
}
verifyAddressPayload("1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L", 1);
API Reference
toBase58(bytes: Uint8Array): string— Encodes into the Bitcoin alphabet. Empty input produces the empty string. Leading zero bytes become leading'1'characters, one per zero byte.fromBase58(s: string): Uint8Array— Decodes into bytes. Leading'1'characters become leading zero bytes. ThrowsCryptoUtilsError(CRYPTO.UTILS.ENCODING.INVALID_INPUT)on any out-of-alphabet character, withcontext.inputtruncated to the first 32 characters of the offending string.
Implementation Notes
Conversion goes through BigInt so arbitrary-length buffers are supported without losing precision. The encoder counts leading zero bytes up front, then converts the remaining bytes to a BigInt, repeatedly divides by 58 to produce characters from least significant to most, and finally prepends one '1' per leading zero byte. The decoder is the reverse; it pre-counts '1' prefix characters, then accumulates n = n * 58 + value into a BigInt, and finally emits bytes by repeated n >>= 8. Base58 is intentionally slower than Base64 — its purpose is human-readability, not throughput. Use Base64/Base64Url for wire formats.