@vbyte/btc-dev
Version:
Batteries-included toolset for plebian bitcoin development
1,507 lines (1,486 loc) • 365 kB
JavaScript
'use strict';
var Check;
(function (Check) {
function is_hex(input) {
return (input.match(/[^a-fA-F0-9]/) === null &&
input.length % 2 === 0);
}
Check.is_hex = is_hex;
function is_bytes(input) {
if (typeof input === 'string' && is_hex(input)) {
return true;
}
else if (input instanceof Uint8Array) {
return true;
}
else if (Array.isArray(input) &&
input.every(e => typeof e === 'number')) {
return true;
}
else {
return false;
}
}
Check.is_bytes = is_bytes;
})(Check || (Check = {}));
var Assert$1;
(function (Assert) {
function within_size(data, size) {
if (data.length > size) {
throw new TypeError(`Data is larger than array size: ${data.length} > ${size}`);
}
}
Assert.within_size = within_size;
function is_hex(hex) {
if (hex.match(/[^a-fA-f0-9]/) !== null) {
throw new TypeError('Invalid characters in hex string: ' + hex);
}
if (hex.length % 2 !== 0) {
throw new Error(`Length of hex string is invalid: ${hex.length}`);
}
}
Assert.is_hex = is_hex;
function is_bytes(bytes) {
if (!Check.is_bytes(bytes)) {
throw new Error('Bytes contains invalid elements: ' + String(bytes));
}
}
Assert.is_bytes = is_bytes;
function is_json(str) {
try {
JSON.parse(str);
}
catch {
throw new TypeError('JSON string is invalid!');
}
}
Assert.is_json = is_json;
function is_safe_int(num) {
if (num > Number.MAX_SAFE_INTEGER) {
throw new TypeError('Number exceeds safe bounds!');
}
}
Assert.is_safe_int = is_safe_int;
})(Assert$1 || (Assert$1 = {}));
const _0n$7 = BigInt(0);
const _255n = BigInt(255);
const _256n = BigInt(256);
function get_big_size(big) {
if (big <= 0xffn)
return 1;
if (big <= 0xffffn)
return 2;
if (big <= 0xffffffffn)
return 4;
if (big <= 0xffffffffffffffffn)
return 8;
if (big <= 0xffffffffffffffffffffffffffffffffn)
return 16;
if (big <= 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn) {
return 32;
}
throw new TypeError('Must specify a fixed buffer size for bigints greater than 32 bytes.');
}
function big_to_bytes(big, size, endian = 'be') {
if (size === undefined)
size = get_big_size(big);
const use_le = (endian === 'le');
const buffer = new ArrayBuffer(size);
const dataView = new DataView(buffer);
let offset = (use_le) ? 0 : size - 1;
while (big > _0n$7) {
const byte = big & _255n;
const num = Number(byte);
if (use_le) {
dataView.setUint8(offset++, num);
}
else {
dataView.setUint8(offset--, num);
}
big = (big - byte) / _256n;
}
return new Uint8Array(buffer);
}
function bytes_to_big(bytes) {
let num = BigInt(0);
for (let i = bytes.length - 1; i >= 0; i--) {
num = (num * _256n) + BigInt(bytes[i]);
}
return BigInt(num);
}
function bigint_replacer(_, v) {
return typeof v === 'bigint'
? `${v}n`
: v;
}
function bigint_reviver(_, v) {
return typeof v === 'string' && /^[0-9]+n$/.test(v)
? BigInt(v.slice(0, -1))
: v;
}
function get_num_size(num) {
if (num <= 0xFF)
return 1;
if (num <= 0xFFFF)
return 2;
if (num <= 0xFFFFFFFF)
return 4;
throw new TypeError('Numbers larger than 4 bytes must specify a fixed size!');
}
function num_to_bytes(num, size, endian = 'be') {
if (size === undefined)
size = get_num_size(num);
const use_le = (endian === 'le');
const buffer = new ArrayBuffer(size);
const dataView = new DataView(buffer);
let offset = (use_le) ? 0 : size - 1;
while (num > 0) {
const byte = num & 255;
if (use_le) {
dataView.setUint8(offset++, num);
}
else {
dataView.setUint8(offset--, num);
}
num = (num - byte) / 256;
}
return new Uint8Array(buffer);
}
function bytes_to_num(bytes) {
let num = 0;
for (let i = bytes.length - 1; i >= 0; i--) {
num = (num * 256) + bytes[i];
Assert$1.is_safe_int(num);
}
return num;
}
function hex_to_bytes(hexstr, size, endian = 'be') {
size = get_hex_size(hexstr, size);
const use_be = (endian === 'be');
const buffer = new ArrayBuffer(size);
const dataView = new DataView(buffer);
let offset = (use_be) ? 0 : size - 1;
for (let i = 0; i < hexstr.length; i += 2) {
const char = hexstr.substring(i, i + 2);
const num = parseInt(char, 16);
if (use_be) {
dataView.setUint8(offset++, num);
}
else {
dataView.setUint8(offset--, num);
}
}
return new Uint8Array(buffer);
}
function bytes_to_hex(bytes) {
let chars = '';
for (let i = 0; i < bytes.length; i++) {
chars += bytes[i].toString(16).padStart(2, '0');
}
return chars;
}
function get_hex_size(hexstr, size) {
Assert$1.is_hex(hexstr);
const len = hexstr.length / 2;
if (size === undefined)
size = len;
if (len > size) {
throw new TypeError(`Hex string is larger than array size: ${len} > ${size}`);
}
return size;
}
function buffer(bytes, size, endian) {
if (bytes instanceof ArrayBuffer) {
return new Uint8Array(bytes);
}
else if (bytes instanceof Uint8Array) {
return create_bytes(bytes, size, endian);
}
else if (typeof bytes === 'string') {
Assert$1.is_hex(bytes);
return hex_to_bytes(bytes, size, endian);
}
else if (typeof bytes === 'bigint') {
return big_to_bytes(bytes, size, endian);
}
else if (typeof bytes === 'number') {
return num_to_bytes(bytes, size, endian);
}
throw new TypeError('Input type not supported:' + typeof bytes);
}
function create_bytes(data, size, endian = 'le') {
if (size === undefined)
size = data.length;
Assert$1.within_size(data, size);
const buffer = new Uint8Array(size).fill(0);
const offset = (endian === 'be') ? 0 : size - data.length;
buffer.set(data, offset);
return buffer;
}
function join_bytes(arr) {
let i, offset = 0;
const size = arr.reduce((len, arr) => len + arr.length, 0);
const buff = new Uint8Array(size);
for (i = 0; i < arr.length; i++) {
const a = arr[i];
buff.set(a, offset);
offset += a.length;
}
return buff;
}
function split_bytes(data_blob, chunk_size, total_size) {
const len = data_blob.length, count = total_size / chunk_size;
if (total_size % chunk_size !== 0) {
throw new TypeError(`Invalid parameters: ${total_size} % ${chunk_size} !== 0`);
}
if (len !== total_size) {
throw new TypeError(`Invalid data stream: ${len} !== ${total_size}`);
}
if (len % chunk_size !== 0) {
throw new TypeError(`Invalid data stream: ${len} % ${chunk_size} !== 0`);
}
const chunks = new Array(count);
for (let i = 0; i < count; i++) {
const idx = i * chunk_size;
chunks[i] = data_blob.subarray(idx, idx + chunk_size);
}
return chunks;
}
function bin_to_bytes(binary) {
const bins = binary.split('').map(Number);
if (bins.length % 8 !== 0) {
throw new Error(`Binary array is invalid length: ${binary.length}`);
}
const bytes = new Uint8Array(bins.length / 8);
for (let i = 0, ct = 0; i < bins.length; i += 8, ct++) {
let byte = 0;
for (let j = 0; j < 8; j++) {
byte |= (bins[i + j] << (7 - j));
}
bytes[ct] = byte;
}
return bytes;
}
function bytes_to_bin(bytes) {
const bin = new Array(bytes.length * 8);
let count = 0;
for (const num of bytes) {
if (num > 255) {
throw new Error(`Invalid byte value: ${num}. Byte values must be between 0 and 255.`);
}
for (let i = 7; i >= 0; i--, count++) {
bin[count] = (num >> i) & 1;
}
}
return bin.join('');
}
const ec = new TextEncoder();
const dc = new TextDecoder();
function str_to_bytes(str) {
return ec.encode(str);
}
function bytes_to_str(bytes) {
return dc.decode(bytes);
}
function get_random_bytes(length = 32) {
if (crypto &&
typeof crypto.getRandomValues === 'function') {
return crypto.getRandomValues(new Uint8Array(length));
}
const pcrypto = crypto;
if (pcrypto &&
pcrypto.randomBytes !== undefined &&
typeof pcrypto.randomBytes === 'function') {
return pcrypto.randomBytes(length);
}
throw new Error('getRandomValues from crypto library is undefined');
}
class Buff extends Uint8Array {
static { this.num = (number, size, endian) => {
return new Buff(number, size, endian);
}; }
static { this.big = (bigint, size, endian) => {
return new Buff(bigint, size, endian);
}; }
static { this.bin = (data, size, endian) => {
const uint = bin_to_bytes(data);
return new Buff(uint, size, endian);
}; }
static { this.uint = (data, size, endian) => {
return new Buff(data, size, endian);
}; }
static { this.str = (data, size, endian) => {
const uint = str_to_bytes(data);
return new Buff(uint, size, endian);
}; }
static { this.hex = (data, size, endian) => {
Assert$1.is_hex(data);
return new Buff(data, size, endian);
}; }
static { this.bytes = (bytes, size, endian) => {
Assert$1.is_bytes(bytes);
return new Buff(bytes, size, endian);
}; }
static { this.json = (data, replacer) => {
replacer = replacer ?? bigint_replacer;
const str = JSON.stringify(data, replacer);
const uint = str_to_bytes(str);
return new Buff(uint);
}; }
static { this.blob = (payload, chunk_size, total_size) => {
const bytes = buffer(payload);
const chunks = split_bytes(bytes, chunk_size, total_size);
return chunks.map(e => new Buff(e));
}; }
static { this.is_equal = (a, b) => {
return new Buff(a).hex === new Buff(b).hex;
}; }
static { this.is_bytes = Check.is_bytes; }
static { this.is_hex = Check.is_hex; }
static random(size = 32) {
const uint = get_random_bytes(size);
return new Buff(uint, size);
}
static now() {
const stamp = Math.floor(Date.now() / 1000);
return new Buff(stamp, 4);
}
constructor(data, size, endian) {
if (data instanceof Buff && size === undefined) {
return data;
}
const buffer$1 = buffer(data, size, endian);
super(buffer$1);
}
get arr() {
return this.to_arr();
}
get big() {
return this.to_big();
}
get bin() {
return this.to_bin();
}
get hex() {
return this.to_hex();
}
get num() {
return this.to_num();
}
get str() {
return this.to_str();
}
get uint() {
return this.to_uint();
}
to_big(endian = 'be') {
const bytes = (endian === 'be')
? this.uint.reverse()
: this.uint;
return bytes_to_big(bytes);
}
to_hex(endian = 'be') {
const bytes = (endian === 'be')
? this.uint
: this.uint.reverse();
return bytes_to_hex(bytes);
}
to_json(reviver) {
if (reviver === undefined) {
reviver = bigint_reviver;
}
const str = bytes_to_str(this);
return JSON.parse(str, reviver);
}
to_num(endian = 'be') {
const bytes = (endian === 'be')
? this.uint.reverse()
: this.uint;
return bytes_to_num(bytes);
}
to_arr() { return [...this]; }
to_bin() { return bytes_to_bin(this); }
to_str() { return bytes_to_str(this); }
to_uint() { return new Uint8Array(this); }
append(data) {
return Buff.join([this, new Buff(data)]);
}
equals(data) {
return new Buff(data).hex === this.hex;
}
prepend(data) {
return Buff.join([new Buff(data), this]);
}
prefix_varint(endian) {
if (this.length === 0)
throw new Error('buffer is empty');
const varint = Buff.varint(this.length, endian);
return this.prepend(varint);
}
reverse() {
super.reverse();
return this;
}
set(array, offset) {
this.set(array, offset);
}
slice(start, end) {
const arr = new Uint8Array(this).slice(start, end);
return new Buff(arr);
}
subarray(begin, end) {
const arr = new Uint8Array(this).subarray(begin, end);
return new Buff(arr);
}
toJSON() {
return this.hex;
}
toString() {
return this.hex;
}
static from(data) {
return new Buff(Uint8Array.from(data));
}
static of(...args) {
return new Buff(Uint8Array.of(...args));
}
static join(arr) {
const bytes = arr.map(e => new Buff(e));
const joined = join_bytes(bytes);
return new Buff(joined);
}
static sort(arr, size) {
const hex = arr.map(e => new Buff(e, size).hex);
hex.sort();
return hex.map(e => Buff.hex(e, size));
}
static varint(num, endian) {
if (num < 0xFD) {
return Buff.num(num, 1);
}
else if (num < 0x10000) {
return Buff.of(0xFD, ...Buff.num(num, 2, endian));
}
else if (num < 0x100000000) {
return Buff.of(0xFE, ...Buff.num(num, 4, endian));
}
else if (BigInt(num) < 0x10000000000000000n) {
return Buff.of(0xFF, ...Buff.num(num, 8, endian));
}
else {
throw new Error(`Value is too large: ${num}`);
}
}
}
class Stream {
constructor(data) {
this.data = new Buff(data);
this.size = this.data.length;
}
peek(size) {
if (size > this.size) {
throw new Error(`Size greater than stream: ${size} > ${this.size}`);
}
return new Buff(this.data.slice(0, size));
}
read(size) {
const chunk = this.peek(size);
this.data = this.data.slice(size);
this.size = this.data.length;
return chunk;
}
varint(endian) {
const num = this.read(1).num;
switch (true) {
case (num >= 0 && num < 0xFD):
return num;
case (num === 0xFD):
return this.read(2).to_num(endian);
case (num === 0xFE):
return this.read(4).to_num(endian);
case (num === 0xFF):
return this.read(8).to_num(endian);
default:
throw new Error(`Varint is out of range: ${num}`);
}
}
}
function sort_obj(obj) {
if (obj instanceof Map || Array.isArray(obj) || typeof obj !== 'object') {
return obj;
}
else {
return Object.keys(obj)
.sort()
.filter(([_, value]) => value !== undefined)
.reduce((sorted, key) => {
sorted[key] = obj[key];
return sorted;
}, {});
}
}
function parse_error(err) {
if (err instanceof Error)
return err.message;
if (typeof err === 'string')
return err;
return String(err);
}
var Test;
(function (Test) {
function exists(value) {
if (typeof value === 'undefined' || value === null) {
return false;
}
return true;
}
Test.exists = exists;
function is_equal(a, b) {
return a === b;
}
Test.is_equal = is_equal;
function is_object(value) {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
Test.is_object = is_object;
function is_deep_equal(a, b) {
if (is_object(a))
a = sort_obj(a);
if (is_object(b))
b = sort_obj(b);
return String(a) === String(b);
}
Test.is_deep_equal = is_deep_equal;
function has_items(array) {
return Array.isArray(array) && array.length > 0;
}
Test.has_items = has_items;
function is_string(value) {
return typeof value === 'string';
}
Test.is_string = is_string;
function is_number(value) {
return Number.isInteger(value) && !Number.isNaN(value);
}
Test.is_number = is_number;
function is_bigint(value) {
return typeof value === 'bigint';
}
Test.is_bigint = is_bigint;
function is_uchar(value) {
return is_number(value) && value >= 0 && value <= 0xFF;
}
Test.is_uchar = is_uchar;
function is_ushort(value) {
return is_number(value) && value >= 0 && value <= 0xFFFF;
}
Test.is_ushort = is_ushort;
function is_uint(value) {
return is_number(value) && value >= 0 && value <= 0xFFFFFFFF;
}
Test.is_uint = is_uint;
function is_u8a(value) {
return value instanceof Uint8Array;
}
Test.is_u8a = is_u8a;
function is_bytes(value) {
return Buff.is_bytes(value);
}
Test.is_bytes = is_bytes;
function is_base58(value) {
if (typeof value !== 'string')
return false;
return /^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$/.test(value);
}
Test.is_base58 = is_base58;
function is_base64(value) {
if (typeof value !== 'string')
return false;
return /^[a-zA-Z0-9+/]+={0,2}$/.test(value);
}
Test.is_base64 = is_base64;
function is_b64url(value) {
if (typeof value !== 'string')
return false;
return /^[a-zA-Z0-9\-_]+={0,2}$/.test(value);
}
Test.is_b64url = is_b64url;
function is_bech32(value) {
if (typeof value !== 'string')
return false;
return /^[a-z]+1[023456789acdefghjklmnpqrstuvwxyz]+$/.test(value);
}
Test.is_bech32 = is_bech32;
function is_hex(value) {
if (!is_string(value))
return false;
return (value.match(/[^a-fA-F0-9]/) === null && value.length % 2 === 0);
}
Test.is_hex = is_hex;
function is_hash(value) {
return (is_string(value) && is_hex(value) && value.length === 64);
}
Test.is_hash = is_hash;
})(Test || (Test = {}));
var Assert;
(function (Assert) {
function ok(value, message) {
if (value === false) {
throw new Error(message ?? 'Assertion failed!');
}
}
Assert.ok = ok;
function exists(value, msg) {
if (!Test.exists(value)) {
throw new Error(msg ?? 'Value is null or undefined!');
}
}
Assert.exists = exists;
function is_empty(value, msg) {
if (value !== null && value !== undefined) {
throw new Error(msg ?? 'value is not null or undefined!');
}
}
Assert.is_empty = is_empty;
function is_instance(value, type, msg) {
if (!(value instanceof type)) {
throw new Error(msg ?? `value is not an instance of ${type.name}`);
}
}
Assert.is_instance = is_instance;
function is_equal(a, b, msg) {
if (!Test.is_equal(a, b)) {
throw new Error(msg ?? `values are not equal: ${String(a)} !== ${String(b)}`);
}
}
Assert.is_equal = is_equal;
function is_object(value, msg) {
if (!Test.is_object(value)) {
throw new Error(msg ?? `value is not an object: ${String(value)}`);
}
}
Assert.is_object = is_object;
function is_deep_equal(a, b, msg) {
if (!Test.is_deep_equal(a, b)) {
throw new Error(msg ?? `values are not deep equal: ${String(a)} !== ${String(b)}`);
}
}
Assert.is_deep_equal = is_deep_equal;
function is_number(value) {
if (!Test.is_number(value)) {
throw new TypeError(`invalid number: ${String(value)}`);
}
}
Assert.is_number = is_number;
function is_bigint(value) {
if (!Test.is_bigint(value)) {
throw new TypeError(`invalid bigint: ${String(value)}`);
}
}
Assert.is_bigint = is_bigint;
function is_hex(value) {
if (!Test.is_hex(value)) {
throw new TypeError(`invalid hex: ${String(value)}`);
}
}
Assert.is_hex = is_hex;
function is_uchar(value) {
if (!Test.is_uchar(value)) {
throw new TypeError(`invalid unsignedchar: ${String(value)}`);
}
}
Assert.is_uchar = is_uchar;
function is_ushort(value) {
if (!Test.is_ushort(value)) {
throw new TypeError(`invalid unsigned short: ${String(value)}`);
}
}
Assert.is_ushort = is_ushort;
function is_uint(value) {
if (!Test.is_uint(value)) {
throw new TypeError(`invalid unsigned int: ${String(value)}`);
}
}
Assert.is_uint = is_uint;
function is_u8a(value) {
if (!Test.is_u8a(value)) {
throw new TypeError(`invalid Uint8Array: ${String(value)}`);
}
}
Assert.is_u8a = is_u8a;
function is_hash(value, msg) {
if (!Test.is_hash(value)) {
throw new TypeError(msg ?? `invalid hash: ${String(value)}`);
}
}
Assert.is_hash = is_hash;
function is_bytes(value, msg) {
if (!Test.is_bytes(value)) {
throw new TypeError(msg ?? `invalid bytes: ${String(value)}`);
}
}
Assert.is_bytes = is_bytes;
function size(input, size, msg) {
const bytes = Buff.bytes(input);
if (bytes.length !== size) {
throw new Error(msg ?? `invalid input size: ${bytes.length} !== ${size}`);
}
}
Assert.size = size;
function has_items(array, err_msg) {
if (!Test.has_items(array)) {
throw new Error(err_msg ?? 'array does not contain any items');
}
}
Assert.has_items = has_items;
function is_base58(value) {
if (!Test.is_base58(value)) {
throw new Error('invalid base58 string');
}
}
Assert.is_base58 = is_base58;
function is_base64(value) {
if (!Test.is_base64(value)) {
throw new Error('invalid base64 string');
}
}
Assert.is_base64 = is_base64;
function is_b64url(value) {
if (!Test.is_b64url(value)) {
throw new Error('invalid base64url string');
}
}
Assert.is_b64url = is_b64url;
function is_bech32(value) {
if (!Test.is_bech32(value)) {
throw new Error('invalid bech32 string');
}
}
Assert.is_bech32 = is_bech32;
})(Assert || (Assert = {}));
const crypto$1 = typeof globalThis === 'object' && 'crypto' in globalThis ? globalThis.crypto : undefined;
/**
* Utilities for hex, bytes, CSPRNG.
* @module
*/
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated (2025-04-30), we can just drop the import.
/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */
function isBytes$1(a) {
return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');
}
/** Asserts something is positive integer. */
function anumber$1(n) {
if (!Number.isSafeInteger(n) || n < 0)
throw new Error('positive integer expected, got ' + n);
}
/** Asserts something is Uint8Array. */
function abytes$1(b, ...lengths) {
if (!isBytes$1(b))
throw new Error('Uint8Array expected');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error('Uint8Array expected of length ' + lengths + ', got length=' + b.length);
}
/** Asserts something is hash */
function ahash(h) {
if (typeof h !== 'function' || typeof h.create !== 'function')
throw new Error('Hash should be wrapped by utils.createHasher');
anumber$1(h.outputLen);
anumber$1(h.blockLen);
}
/** Asserts a hash instance has not been destroyed / finished */
function aexists(instance, checkFinished = true) {
if (instance.destroyed)
throw new Error('Hash instance has been destroyed');
if (checkFinished && instance.finished)
throw new Error('Hash#digest() has already been called');
}
/** Asserts output is properly-sized byte array */
function aoutput(out, instance) {
abytes$1(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error('digestInto() expects output buffer of length at least ' + min);
}
}
/** Zeroize a byte array. Warning: JS provides no guarantees. */
function clean(...arrays) {
for (let i = 0; i < arrays.length; i++) {
arrays[i].fill(0);
}
}
/** Create DataView of an array for easy byte-level manipulation. */
function createView(arr) {
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
}
/** The rotate right (circular right shift) operation for uint32 */
function rotr(word, shift) {
return (word << (32 - shift)) | (word >>> shift);
}
/** The rotate left (circular left shift) operation for uint32 */
function rotl(word, shift) {
return (word << shift) | ((word >>> (32 - shift)) >>> 0);
}
// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex
const hasHexBuiltin = /* @__PURE__ */ (() =>
// @ts-ignore
typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();
// Array where index 0xf0 (240) is mapped to string 'f0'
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* Convert byte array to hex string. Uses built-in function, when available.
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
abytes$1(bytes);
// @ts-ignore
if (hasHexBuiltin)
return bytes.toHex();
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}
return hex;
}
// We use optimized technique to convert hex string to byte array
const asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
function asciiToBase16(ch) {
if (ch >= asciis._0 && ch <= asciis._9)
return ch - asciis._0; // '2' => 50-48
if (ch >= asciis.A && ch <= asciis.F)
return ch - (asciis.A - 10); // 'B' => 66-(65-10)
if (ch >= asciis.a && ch <= asciis.f)
return ch - (asciis.a - 10); // 'b' => 98-(97-10)
return;
}
/**
* Convert hex string to byte array. Uses built-in function, when available.
* @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
*/
function hexToBytes(hex) {
if (typeof hex !== 'string')
throw new Error('hex string expected, got ' + typeof hex);
// @ts-ignore
if (hasHexBuiltin)
return Uint8Array.fromHex(hex);
const hl = hex.length;
const al = hl / 2;
if (hl % 2)
throw new Error('hex string expected, got unpadded hex of length ' + hl);
const array = new Uint8Array(al);
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
const n1 = asciiToBase16(hex.charCodeAt(hi));
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
if (n1 === undefined || n2 === undefined) {
const char = hex[hi] + hex[hi + 1];
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
}
array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163
}
return array;
}
/**
* Converts string to bytes using UTF8 encoding.
* @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])
*/
function utf8ToBytes(str) {
if (typeof str !== 'string')
throw new Error('string expected');
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
abytes$1(data);
return data;
}
/** Copies several Uint8Arrays into one. */
function concatBytes(...arrays) {
let sum = 0;
for (let i = 0; i < arrays.length; i++) {
const a = arrays[i];
abytes$1(a);
sum += a.length;
}
const res = new Uint8Array(sum);
for (let i = 0, pad = 0; i < arrays.length; i++) {
const a = arrays[i];
res.set(a, pad);
pad += a.length;
}
return res;
}
/** For runtime check if class implements interface */
class Hash {
}
/** Wraps hash function, creating an interface on top of it */
function createHasher(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */
function randomBytes(bytesLength = 32) {
if (crypto$1 && typeof crypto$1.getRandomValues === 'function') {
return crypto$1.getRandomValues(new Uint8Array(bytesLength));
}
// Legacy Node.js compatibility
if (crypto$1 && typeof crypto$1.randomBytes === 'function') {
return Uint8Array.from(crypto$1.randomBytes(bytesLength));
}
throw new Error('crypto.getRandomValues must be defined');
}
/**
* Internal Merkle-Damgard hash utils.
* @module
*/
/** Polyfill for Safari 14. https://caniuse.com/mdn-javascript_builtins_dataview_setbiguint64 */
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === 'function')
return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
/** Choice: a ? b : c */
function Chi(a, b, c) {
return (a & b) ^ (~a & c);
}
/** Majority function, true if any two inputs is true. */
function Maj(a, b, c) {
return (a & b) ^ (a & c) ^ (b & c);
}
/**
* Merkle-Damgard hash construction base class.
* Could be used to create MD5, RIPEMD, SHA1, SHA2.
*/
class HashMD extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
aexists(this);
data = toBytes(data);
abytes$1(data);
const { view, buffer, blockLen } = this;
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
// Fast path: we have at least one block in input, cast it to view and process
if (take === blockLen) {
const dataView = createView(data);
for (; blockLen <= len - pos; pos += blockLen)
this.process(dataView, pos);
continue;
}
buffer.set(data.subarray(pos, pos + take), this.pos);
this.pos += take;
pos += take;
if (this.pos === blockLen) {
this.process(view, 0);
this.pos = 0;
}
}
this.length += data.length;
this.roundClean();
return this;
}
digestInto(out) {
aexists(this);
aoutput(out, this);
this.finished = true;
// Padding
// We can avoid allocation of buffer for padding completely if it
// was previously not allocated here. But it won't change performance.
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
// append the bit '1' to the message
buffer[pos++] = 0b10000000;
clean(this.buffer.subarray(pos));
// we have less than padOffset left in buffer, so we cannot put length in
// current block, need process it and pad again
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
// Pad until full block byte with zeros
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
// So we just write lowest 64 bits of that value.
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4)
throw new Error('_sha2: outputLen should be aligned to 32bit');
const outLen = len / 4;
const state = this.get();
if (outLen > state.length)
throw new Error('_sha2: outputLen bigger than state');
for (let i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.destroyed = destroyed;
to.finished = finished;
to.length = length;
to.pos = pos;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
clone() {
return this._cloneInto();
}
}
/**
* Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.
* Check out `test/misc/sha2-gen-iv.js` for recomputation guide.
*/
/** Initial SHA256 state. Bits 0..32 of frac part of sqrt of primes 2..19 */
const SHA256_IV = /* @__PURE__ */ Uint32Array.from([
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
]);
/**
* SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.
* SHA256 is the fastest hash implementable in JS, even faster than Blake3.
* Check out [RFC 4634](https://datatracker.ietf.org/doc/html/rfc4634) and
* [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
* @module
*/
/**
* Round constants:
* First 32 bits of fractional parts of the cube roots of the first 64 primes 2..311)
*/
// prettier-ignore
const SHA256_K = /* @__PURE__ */ Uint32Array.from([
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]);
/** Reusable temporary buffer. "W" comes straight from spec. */
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends HashMD {
constructor(outputLen = 32) {
super(64, outputLen, 8, false);
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
this.A = SHA256_IV[0] | 0;
this.B = SHA256_IV[1] | 0;
this.C = SHA256_IV[2] | 0;
this.D = SHA256_IV[3] | 0;
this.E = SHA256_IV[4] | 0;
this.F = SHA256_IV[5] | 0;
this.G = SHA256_IV[6] | 0;
this.H = SHA256_IV[7] | 0;
}
get() {
const { A, B, C, D, E, F, G, H } = this;
return [A, B, C, D, E, F, G, H];
}
// prettier-ignore
set(A, B, C, D, E, F, G, H) {
this.A = A | 0;
this.B = B | 0;
this.C = C | 0;
this.D = D | 0;
this.E = E | 0;
this.F = F | 0;
this.G = G | 0;
this.H = H | 0;
}
process(view, offset) {
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
}
// Compression function main loop, 64 rounds
let { A, B, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
const T2 = (sigma0 + Maj(A, B, C)) | 0;
H = G;
G = F;
F = E;
E = (D + T1) | 0;
D = C;
C = B;
B = A;
A = (T1 + T2) | 0;
}
// Add the compressed chunk to the current hash value
A = (A + this.A) | 0;
B = (B + this.B) | 0;
C = (C + this.C) | 0;
D = (D + this.D) | 0;
E = (E + this.E) | 0;
F = (F + this.F) | 0;
G = (G + this.G) | 0;
H = (H + this.H) | 0;
this.set(A, B, C, D, E, F, G, H);
}
roundClean() {
clean(SHA256_W);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
clean(this.buffer);
}
}
/**
* SHA2-256 hash function from RFC 4634.
*
* It is the fastest JS hash, even faster than Blake3.
* To break sha256 using birthday attack, attackers need to try 2^128 hashes.
* BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.
*/
const sha256$1 = /* @__PURE__ */ createHasher(() => new SHA256());
/**
* HMAC: RFC2104 message authentication code.
* @module
*/
class HMAC extends Hash {
constructor(hash, _key) {
super();
this.finished = false;
this.destroyed = false;
ahash(hash);
const key = toBytes(_key);
this.iHash = hash.create();
if (typeof this.iHash.update !== 'function')
throw new Error('Expected instance of class which extends utils.Hash');
this.blockLen = this.iHash.blockLen;
this.outputLen = this.iHash.outputLen;
const blockLen = this.blockLen;
const pad = new Uint8Array(blockLen);
// blockLen can be bigger than outputLen
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
for (let i = 0; i < pad.length; i++)
pad[i] ^= 0x36;
this.iHash.update(pad);
// By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
this.oHash = hash.create();
// Undo internal XOR && apply outer XOR
for (let i = 0; i < pad.length; i++)
pad[i] ^= 0x36 ^ 0x5c;
this.oHash.update(pad);
clean(pad);
}
update(buf) {
aexists(this);
this.iHash.update(buf);
return this;
}
digestInto(out) {
aexists(this);
abytes$1(out, this.outputLen);
this.finished = true;
this.iHash.digestInto(out);
this.oHash.update(out);
this.oHash.digestInto(out);
this.destroy();
}
digest() {
const out = new Uint8Array(this.oHash.outputLen);
this.digestInto(out);
return out;
}
_cloneInto(to) {
// Create new instance without calling constructor since key already in state and we don't know it.
to || (to = Object.create(Object.getPrototypeOf(this), {}));
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
to = to;
to.finished = finished;
to.destroyed = destroyed;
to.blockLen = blockLen;
to.outputLen = outputLen;
to.oHash = oHash._cloneInto(to.oHash);
to.iHash = iHash._cloneInto(to.iHash);
return to;
}
clone() {
return this._cloneInto();
}
destroy() {
this.destroyed = true;
this.oHash.destroy();
this.iHash.destroy();
}
}
/**
* HMAC: RFC2104 message authentication code.
* @param hash - function that would be used e.g. sha256
* @param key - message key
* @param message - message data
* @example
* import { hmac } from '@noble/hashes/hmac';
* import { sha256 } from '@noble/hashes/sha2';
* const mac1 = hmac(sha256, 'key', 'message');
*/
const hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
hmac.create = (hash, key) => new HMAC(hash, key);
/**
* Hex, bytes and number utilities.
* @module
*/
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const _0n$6 = /* @__PURE__ */ BigInt(0);
const _1n$5 = /* @__PURE__ */ BigInt(1);
function abool(title, value) {
if (typeof value !== 'boolean')
throw new Error(title + ' boolean expected, got ' + value);
}
// Used in weierstrass, der
function numberToHexUnpadded(num) {
const hex = num.toString(16);
return hex.length & 1 ? '0' + hex : hex;
}
function hexToNumber(hex) {
if (typeof hex !== 'string')
throw new Error('hex string expected, got ' + typeof hex);
return hex === '' ? _0n$6 : BigInt('0x' + hex); // Big Endian
}
// BE: Big Endian, LE: Little Endian
function bytesToNumberBE(bytes) {
return hexToNumber(bytesToHex(bytes));
}
function bytesToNumberLE(bytes) {
abytes$1(bytes);
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
}
function numberToBytesBE(n, len) {
return hexToBytes(n.toString(16).padStart(len * 2, '0'));
}
function numberToBytesLE(n, len) {
return numberToBytesBE(n, len).reverse();
}
/**
* Takes hex string or Uint8Array, converts to Uint8Array.
* Validates output length.
* Will throw error for other types.
* @param title descriptive title for an error e.g. 'secret key'
* @param hex hex string or Uint8Array
* @param expectedLength optional, will compare to result array's length
* @returns
*/
function ensureBytes(title, hex, expectedLength) {
let res;
if (typeof hex === 'string') {
try {
res = hexToBytes(hex);
}
catch (e) {
throw new Error(title + ' must be hex string or Uint8Array, cause: ' + e);
}
}
else if (isBytes$1(hex)) {
// Uint8Array.from() instead of hash.slice() because node.js Buffer
// is instance of Uint8Array, and its slice() creates **mutable** copy
res = Uint8Array.from(hex);
}
else {
throw new Error(title + ' must be hex string or Uint8Array');
}
const len = res.length;
if (typeof expectedLength === 'number' && len !== expectedLength)
throw new Error(title + ' of length ' + expectedLength + ' expected, got ' + len);
return res;
}
/**
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
*/
// export const utf8ToBytes: typeof utf8ToBytes_ = utf8ToBytes_;
/**
* Converts bytes to string using UTF8 encoding.
* @example bytesToUtf8(Uint8Array.from([97, 98, 99])) // 'abc'
*/
// export const bytesToUtf8: typeof bytesToUtf8_ = bytesToUtf8_;
// Is positive bigint
const isPosBig = (n) => typeof n === 'bigint' && _0n$6 <= n;
function inRange(n, min, max) {
return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
}
/**
* Asserts min <= n < max. NOTE: It's < max and not <= max.
* @example
* aInRange('x', x, 1n, 256n); // would assume x is in (1n..255n)
*/
function aInRange(title, n, min, max) {
// Why min <= n < max and not a (min < n < max) OR b (min <= n <= max)?
// consider P=256n, min=0n, max=P
// - a for min=0 would require -1: `inRange('x', x, -1n, P)`
// - b would commonly require subtraction: `inRange('x', x, 0n, P - 1n)`
// - our way is the cleanest: `inRange('x', x, 0n, P)
if (!inRange(n, min, max))
throw new Error('expected valid ' + title + ': ' + min + ' <= n < ' + max + ', got ' + n);
}
// Bit operations
/**
* Calculates amount of bits in a bigint.
* Same as `n.toString(2).length`
* TODO: merge with nLength in modular
*/
function bitLen(n) {
let len;
for (len = 0; n > _0n$6; n >>= _1n$5, len += 1)
;
return len;
}
/**
* Calculate mask for N bits. Not using ** operator with bigints because of old engines.
* Same as BigInt(`0b${Array(i).fill('1').join('')}`)
*/
const bitMask = (n) => (_1n$5 << BigInt(n)) - _1n$5;
/**
* Minimal HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
* @returns function that will call DRBG until 2nd arg returns something meaningful
* @example
* const drbg = createHmacDRBG<Key>(32, 32, hmac);
* drbg(seed, bytesToKey); // bytesToKey must return Key or undefined
*/
function createHmacDrbg(hashLen, qByteLen, hmacFn) {
if (typeof hashLen !== 'number' || hashLen < 2)
throw new Error('hashLen must be a number');
if (typeof qByteLen !== 'number' || qByteLen < 2)
throw new Error('qByteLen must be a number');
if (typeof hmacFn !== 'function')
throw new Error('hmacFn must be a function');
// Step B, Step C: set hashLen to 8*ceil(hlen/8)
const u8n = (len) => new Uint8Array(len); // creates Uint8Array
const u8of = (byte) => Uint8Array.of(byte); // another shortcut
let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same
let i = 0; // Iterations counter, will throw when over 1000
const reset = () => {
v.fill(1);
k.fill(0);
i = 0;
};
const h = (...b) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)
const reseed = (seed = u8n(0)) => {
// HMAC-DRBG reseed() function. Steps D-G
k = h(u8of(0x00), seed); // k = hmac(k || v || 0x00 || seed)
v = h(); // v = hmac(k || v)
if (seed.length === 0)
return;
k = h(u8of(0x01), seed); // k = hmac(k || v || 0x01 || seed)
v = h(); // v = hmac(k || v)
};
const gen = () => {
// HMAC-DRBG generate() function
if (i++ >= 1000)
throw new Error('drbg: tried 1000 values');
let len = 0;
const out = [];
while (len < qByteLen) {
v = h();
const sl = v.slice();
out.push(sl);
len += v.length;
}
return concatBytes(...out);
};
const genUntil = (seed, pred) => {
reset();
reseed(seed); // Steps D-G
let res = undefined; // Step H: grind until k is in [1..n-1]
while (!(res = pred(gen())))
reseed();
reset();
return res;
};
return genUntil;
}
function _validateObject(object, fields, optFields = {}) {
if (!object || typeof object !== 'object')
throw new Error('expected valid options object');
function checkField(fieldName, expectedType, isOpt) {
const val = object[fieldName];
if (isOpt && val === undefined)
return;
const current = typeof val;
if (current !== expectedType || val === null)
throw new Error(`param "${fieldName}" is invalid: expected ${expectedType}, got ${current}`);
}
Object.entries(fields).forEach(([k, v]) => checkField(k, v, false));
Object.entries(optFields).forEach(([k, v]) => checkField(k, v, true));
}
/**
* Memoizes (caches) computation result.
* Uses WeakMap: the value is going auto-cleaned by GC after last reference is removed.
*/
function memoized(fn) {
const map = new WeakMap();
return (arg, ...args) => {
const val = map.get(arg);
if (val !== undefined)
return val;
const computed = fn(arg, ...args);
map.set(arg, computed);
return computed;
};
}
/**
* Utils for modular division and fields.
* Field over 11 is a finite (Galois) field is integer number operations `mod 11`.
* There is no division: it is replaced by modular multiplicative inverse.
* @module
*/
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// prettier-ignore
const _0n$5 = BigInt(0), _1n$4 = BigInt(1), _2n$3 = /* @__PURE__ */ BigInt(2),