@silvana-one/mina-utils
Version:
Silvana Mina Utils
88 lines (81 loc) • 2.99 kB
text/typescript
// URL friendly base64 encoding
const TABLE =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
export function bigintToBase56(value: bigint): string {
const digits = toBase(value, 56n);
//console.log("digits:", digits);
const str = digits.map((x) => TABLE[Number(x)]).join("");
//console.log("str:", str);
return str;
}
export function bigintFromBase56(str: string): bigint {
const base56Digits = str.split("").map((x) => BigInt(TABLE.indexOf(x)));
const x = fromBase(base56Digits, 56n);
return x;
}
export function bigintToBase64(value: bigint): string {
const digits = toBase(value, 64n);
//console.log("digits:", digits);
const str = digits.map((x) => TABLE[Number(x)]).join("");
//console.log("str:", str);
return str;
}
export function bigintFromBase64(str: string): bigint {
const base64Digits = str.split("").map((x) => BigInt(TABLE.indexOf(x)));
const x = fromBase(base64Digits, 64n);
return x;
}
export function fromBase(digits: bigint[], base: bigint) {
if (base <= 0n) throw Error("fromBase: base must be positive");
// compute powers base, base^2, base^4, ..., base^(2^k)
// with largest k s.t. n = 2^k < digits.length
let basePowers = [];
for (let power = base, n = 1; n < digits.length; power **= 2n, n *= 2) {
basePowers.push(power);
}
let k = basePowers.length;
// pad digits array with zeros s.t. digits.length === 2^k
digits = digits.concat(Array(2 ** k - digits.length).fill(0n));
// accumulate [x0, x1, x2, x3, ...] -> [x0 + base*x1, x2 + base*x3, ...] -> [x0 + base*x1 + base^2*(x2 + base*x3), ...] -> ...
// until we end up with a single element
for (let i = 0; i < k; i++) {
let newDigits = Array(digits.length >> 1);
let basePower = basePowers[i];
for (let j = 0; j < newDigits.length; j++) {
newDigits[j] = digits[2 * j] + basePower * digits[2 * j + 1];
}
digits = newDigits;
}
console.assert(digits.length === 1);
let [digit] = digits;
return digit;
}
export function toBase(x: bigint, base: bigint) {
if (base <= 0n) throw Error("toBase: base must be positive");
// compute powers base, base^2, base^4, ..., base^(2^k)
// with largest k s.t. base^(2^k) < x
let basePowers = [];
for (let power = base; power <= x; power **= 2n) {
basePowers.push(power);
}
let digits = [x]; // single digit w.r.t base^(2^(k+1))
// successively split digits w.r.t. base^(2^j) into digits w.r.t. base^(2^(j-1))
// until we arrive at digits w.r.t. base
let k = basePowers.length;
for (let i = 0; i < k; i++) {
let newDigits = Array(2 * digits.length);
let basePower = basePowers[k - 1 - i];
for (let j = 0; j < digits.length; j++) {
let x = digits[j];
let high = x / basePower;
newDigits[2 * j + 1] = high;
newDigits[2 * j] = x - high * basePower;
}
digits = newDigits;
}
// pop "leading" zero digits
while (digits[digits.length - 1] === 0n) {
digits.pop();
}
return digits;
}