src/address/base58.ts
v0.1.0 · 1.7 KB
// Canonical base58 addresses are case-sensitive.
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; // privacy-allow: public canonical base58 alphabet
const INDEX = new Map<string, number>([...ALPHABET].map((c, i) => [c, i]));
export function base58Decode(s: string): Uint8Array | null {
if (typeof s !== 'string' || s.length === 0 || s.length > 128) return null;
const bytes: number[] = [];
for (const ch of s) {
const v = INDEX.get(ch);
if (v === undefined) return null;
let carry = v;
for (let i = 0; i < bytes.length; i++) {
carry += bytes[i]! * 58;
bytes[i] = carry & 0xff;
carry >>= 8;
}
while (carry > 0) {
bytes.push(carry & 0xff);
carry >>= 8;
}
}
for (let i = 0; i < s.length && s[i] === '1'; i++) bytes.push(0);
return Uint8Array.from(bytes.reverse());
}
export function base58Encode(data: Uint8Array): string {
const digits: number[] = [];
for (const byte of data) {
let carry = byte;
for (let i = 0; i < digits.length; i++) {
carry += digits[i]! << 8;
digits[i] = carry % 58;
carry = Math.floor(carry / 58);
}
while (carry > 0) {
digits.push(carry % 58);
carry = Math.floor(carry / 58);
}
}
let out = '';
for (let i = 0; i < data.length && data[i] === 0; i++) out += '1';
for (let i = digits.length - 1; i >= 0; i--) out += ALPHABET[digits[i]!];
return out;
}
export function isBase58Pubkey(s: string): boolean {
const b = base58Decode(s);
return b !== null && b.length === 32 && base58Encode(b) === s;
}
export function isSignatureString(s: string): boolean {
const b = base58Decode(s);
return b !== null && b.length === 64 && base58Encode(b) === s;
}