Files
brk/website_next/wallets/derive/base58.js
T
2026-06-17 11:25:42 +02:00

115 lines
2.2 KiB
JavaScript

import { bytesEqual, bytesToBigInt, concatBytes, createBytes } from "./bytes.js";
import { checksum as createChecksum } from "./hash.js";
const alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
const base = 58n;
/**
* @param {string} character
*/
function readBase58Character(character) {
const index = alphabet.indexOf(character);
if (index === -1) {
throw new Error(`Invalid Base58 character: ${character}`);
}
return index;
}
/**
* @param {string} text
*/
function countLeadingZeros(text) {
let count = 0;
while (text[count] === "1") {
count += 1;
}
return count;
}
/**
* @param {Uint8Array} bytes
*/
function countLeadingZeroBytes(bytes) {
let count = 0;
while (bytes[count] === 0) {
count += 1;
}
return count;
}
/**
* @param {string} text
*/
function decodeBase58(text) {
let value = 0n;
for (const character of text) {
value = value * base + BigInt(readBase58Character(character));
}
const leadingZeros = countLeadingZeros(text);
const decoded = /** @type {number[]} */ ([]);
while (value > 0n) {
decoded.push(Number(value & 0xffn));
value >>= 8n;
}
decoded.reverse();
const bytes = createBytes(leadingZeros + decoded.length);
bytes.set(decoded, leadingZeros);
return bytes;
}
/**
* @param {Uint8Array} bytes
*/
function encodeBase58(bytes) {
let value = bytesToBigInt(bytes);
let text = "";
while (value > 0n) {
const index = Number(value % base);
text = alphabet[index] + text;
value /= base;
}
return "1".repeat(countLeadingZeroBytes(bytes)) + text;
}
/**
* @param {string} text
*/
export async function decodeBase58Check(text) {
const bytes = decodeBase58(text);
if (bytes.length < 4) {
throw new Error("Invalid Base58Check payload");
}
const payload = bytes.slice(0, -4);
const expected = await createChecksum(payload);
const actual = bytes.slice(-4);
if (!bytesEqual(actual, expected)) {
throw new Error("Invalid Base58Check checksum");
}
return payload;
}
/**
* @param {Uint8Array} payload
*/
export async function encodeBase58Check(payload) {
return encodeBase58(concatBytes([payload, await createChecksum(payload)]));
}