mirror of
https://github.com/stjet/banani.git
synced 2025-12-29 17:49:24 +00:00
92 lines
3.1 KiB
TypeScript
92 lines
3.1 KiB
TypeScript
import * as nacl from "tweetnacl"; //currently unused
|
|
import blake2b from "blake2b"; //currently unused
|
|
|
|
// byte related
|
|
|
|
const HEX_CHARS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
|
|
|
|
//sigh... https://www.prussiafan.club/posts/hex-to-bytes-and-back/
|
|
export function uint8array_to_hex(uint8array: Uint8Array): string {
|
|
let hex: string = "";
|
|
for (let i = 0; i < uint8array.length; i++) {
|
|
hex += HEX_CHARS[Math.floor(uint8array[i] / 16)] + HEX_CHARS[uint8array[i] % 16];
|
|
}
|
|
return hex;
|
|
}
|
|
|
|
//assumes the hex length is multiple of 2
|
|
export function hex_to_uint8array(hex: string): Uint8Array {
|
|
let uint8array: Uint8Array = new Uint8Array(hex.length / 2);
|
|
for (let i = 0; i < hex.length / 2; i++) {
|
|
uint8array[i] = HEX_CHARS.indexOf(hex[i * 2]) * 16 + HEX_CHARS.indexOf(hex[i * 2 + 1]);
|
|
}
|
|
return uint8array;
|
|
}
|
|
|
|
export function int_to_uint8array(int: number, len: number): Uint8Array {
|
|
let uint8array: Uint8Array = new Uint8Array(len);
|
|
for (let i = 1; i <= len; i++) {
|
|
if (i === 1) {
|
|
uint8array[len - i] = int % (16 ** 2);
|
|
} else {
|
|
let subbed_int = int;
|
|
for (let j = i - 1; j > 0; j--) {
|
|
subbed_int -= uint8array[len - j] * (16 ** (2 * (j - 1)));
|
|
}
|
|
uint8array[len - i] = Math.floor((subbed_int) / (16 ** (2 * (i - 1))));
|
|
}
|
|
}
|
|
return uint8array;
|
|
}
|
|
|
|
//
|
|
|
|
// whole and raw related
|
|
|
|
const BANANO_DECIMALS: number = 29;
|
|
|
|
export type Whole = `${number}`; //number can include non-base-10 formats... but whatever, we can assume users will pass in only base-10 because they are normal for the most part
|
|
|
|
/** Turn whole Bananos (string) into raw Bananos (BigInt) */
|
|
export function whole_to_raw(whole: Whole, decimals = BANANO_DECIMALS): BigInt {
|
|
let raw: BigInt;
|
|
if (whole.includes(".")) {
|
|
let parts = whole.split(".");
|
|
if (0 > (decimals - parts[1].length)) throw Error(`Too many decimals, cannot exceed ${decimals}`)
|
|
raw = BigInt(parts[0]) * (BigInt(10) ** BigInt(decimals)) + BigInt(parts[1]) * (BigInt(10) ** BigInt(decimals - parts[1].length));
|
|
} else {
|
|
raw = BigInt(whole) * (BigInt(10) ** BigInt(decimals));
|
|
}
|
|
return raw;
|
|
}
|
|
|
|
/** Turn raw Bananos (BigInt) into whole Bananos (string) */
|
|
export function raw_to_whole(raw: BigInt, decimals = BANANO_DECIMALS): Whole {
|
|
const raw_string: string = raw.toString();
|
|
let whole_string: string;
|
|
if (raw_string.length > decimals) {
|
|
whole_string = raw_string.slice(0, -decimals) + "." + raw_string.slice(-decimals);
|
|
} else {
|
|
let r: number = decimals - raw_string.length;
|
|
whole_string = "0." + "0".repeat(r > 0 ? r : 0) + raw_string;
|
|
}
|
|
//truncate any extra zeroes
|
|
let cl: number = whole_string.length;
|
|
for (let c = 0; c < cl; c++) {
|
|
if (whole_string.slice(-1) === "0" || whole_string.slice(-1) === ".") {
|
|
whole_string = whole_string.slice(0, -1);
|
|
}
|
|
}
|
|
return whole_string as Whole;
|
|
}
|
|
|
|
// crypto related
|
|
|
|
export function get_private_key_from_seed(seed: string, index: number): string {
|
|
//index is 4 bytes
|
|
return blake2b(32).update(hex_to_uint8array(seed)).update(int_to_uint8array(index, 4)).digest("hex")
|
|
}
|
|
|
|
//
|
|
|