Files
skills/docs/security-stack/crypto/crypto-utils/src/encoding/base58/base58.md
2026-05-29 08:20:56 +01:00

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_INPUT on 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. Throws CryptoUtilsError(CRYPTO.UTILS.ENCODING.INVALID_INPUT) on any out-of-alphabet character, with context.input truncated 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.