@hdwallet/core
Version:
A complete Hierarchical Deterministic (HD) Wallet generator for 200+ cryptocurrencies, built with TypeScript.
848 lines • 28.7 kB
JavaScript
;
// SPDX-License-Identifier: MIT
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBytes = getBytes;
exports.toBuffer = toBuffer;
exports.hexToBytes = hexToBytes;
exports.bytesToHex = bytesToHex;
exports.bytesToString = bytesToString;
exports.randomBytes = randomBytes;
exports.bytesToInteger = bytesToInteger;
exports.ensureString = ensureString;
exports.stringToInteger = stringToInteger;
exports.equalBytes = equalBytes;
exports.integerToBytes = integerToBytes;
exports.concatBytes = concatBytes;
exports.bytesToBinaryString = bytesToBinaryString;
exports.binaryStringToInteger = binaryStringToInteger;
exports.integerToBinaryString = integerToBinaryString;
exports.binaryStringToBytes = binaryStringToBytes;
exports.isAllEqual = isAllEqual;
exports.generatePassphrase = generatePassphrase;
exports.getHmac = getHmac;
exports.excludeKeys = excludeKeys;
exports.pathToIndexes = pathToIndexes;
exports.indexesToPath = indexesToPath;
exports.normalizeIndex = normalizeIndex;
exports.normalizeDerivation = normalizeDerivation;
exports.indexTupleToInteger = indexTupleToInteger;
exports.indexTupleToString = indexTupleToString;
exports.indexStringToTuple = indexStringToTuple;
exports.xor = xor;
exports.addNoCarry = addNoCarry;
exports.multiplyScalarNoCarry = multiplyScalarNoCarry;
exports.isBitsSet = isBitsSet;
exports.areBitsSet = areBitsSet;
exports.setBit = setBit;
exports.setBits = setBits;
exports.resetBit = resetBit;
exports.resetBits = resetBits;
exports.bytesReverse = bytesReverse;
exports.convertBits = convertBits;
exports.bytesChunkToWords = bytesChunkToWords;
exports.wordsToBytesChunk = wordsToBytesChunk;
exports.toCamelCase = toCamelCase;
exports.ensureTypeMatch = ensureTypeMatch;
const utils_1 = require("@noble/hashes/utils");
const exceptions_1 = require("./exceptions");
/**
* Converts input data to a Uint8Array.
* @param data - Input data as a string, number array, Uint8Array, or null/undefined.
* @param encoding - Encoding to use if input is a string ('hex', 'utf8', 'base64'). Default is 'hex'.
* @returns Uint8Array representation of the input data.
*/
function getBytes(data, encoding = 'hex') {
if (data == null) {
return new Uint8Array();
}
// Already a Uint8Array?
if (data instanceof Uint8Array) {
return data;
}
// Array of numbers?
if (Array.isArray(data)) {
return new Uint8Array(data);
}
// From here on: data is a string
const str = data;
switch (encoding) {
case 'hex': {
// Strip optional 0x/0X
let s = str.startsWith('0x') || str.startsWith('0X') ? str.slice(2) : str;
// Pad odd length
if (s.length % 2 === 1)
s = '0' + s;
// Split into byte-pairs and parse
return Uint8Array.from(s.match(/.{1,2}/g).map(b => parseInt(b, 16)));
}
case 'utf8':
return new TextEncoder().encode(str);
case 'base64':
// atob → binary-string → map char codes
return Uint8Array.from(atob(str), c => c.charCodeAt(0));
default:
throw new Error(`Unsupported encoding: ${encoding}`);
}
}
/**
* Converts input to a Uint8Array (buffer).
* @param input - Input as a string, ArrayBuffer, or Array-like number array.
* @param encoding - Encoding for string inputs ('utf8', 'hex', 'base64'). Default is 'utf8'.
* @returns Uint8Array representation of input.
*/
function toBuffer(input, encoding = 'utf8') {
if (typeof input === 'string') {
switch (encoding) {
case 'utf8':
// UTF-8 encode a string
return new TextEncoder().encode(input);
case 'base64':
// atob gives a binary‐string; map char→byte
return Uint8Array.from(atob(input), c => c.charCodeAt(0));
case 'hex':
// split every two hex digits → parse → byte
return Uint8Array.from(input.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
default:
throw new Error(`Unsupported encoding: ${encoding}`);
}
}
// If it's already an ArrayBuffer or TypedArray
if (input instanceof ArrayBuffer) {
return new Uint8Array(input);
}
if (ArrayBuffer.isView(input)) {
return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
}
// Fallback: try Array-like (e.g. number[])
return Uint8Array.from(input);
}
/**
* Converts a hex string to a Uint8Array.
* @param hex - Hexadecimal string (optionally prefixed with '0x').
* @returns Uint8Array representing the hex string.
* @throws Error if hex string length is not even.
*/
function hexToBytes(hex) {
const normalized = hex.startsWith('0x') ? hex.slice(2) : hex;
if (normalized.length % 2 !== 0) {
throw new Error(`Invalid hex string length: ${normalized.length}`);
}
const bytes = new Uint8Array(normalized.length / 2);
for (let i = 0; i < bytes.length; i++) {
bytes[i] = parseInt(normalized.substr(i * 2, 2), 16);
}
return bytes;
}
/**
* Converts a Uint8Array to a hex string.
* @param bytes - Data to convert.
* @param prefix - Whether to add '0x' prefix. Default is false.
* @returns Hexadecimal string.
*/
function bytesToHex(bytes, prefix = false) {
const hex = Array.from(bytes)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
return prefix ? `0x${hex}` : hex;
}
/**
* Converts a string or Uint8Array to a hex string.
* @param data - Input string or Uint8Array.
* @returns Hexadecimal string representation of input.
*/
function bytesToString(data) {
if (data == null ||
(typeof data === 'string' && data.length === 0) ||
(data instanceof Uint8Array && data.length === 0)) {
return '';
}
if (typeof data === 'string') {
// If it’s a valid even-length hex string (0–9, A–F, a–f), return it lowercased:
if (data.length % 2 === 0 && /^[0-9A-Fa-f]+$/.test(data)) {
return data.toLowerCase();
}
// Otherwise treat `data` as UTF-8 text: encode to Uint8Array then to hex
const encoder = new TextEncoder();
const bytes = encoder.encode(data);
return bytesToHex(bytes);
}
// Uint8Array case: just convert those bytes to hex
return bytesToHex(data);
}
/**
* Generates cryptographically secure random bytes.
* @param len - Number of random bytes to generate.
* @returns Uint8Array of random bytes.
* @throws Error if length is not a positive integer.
*/
function randomBytes(len) {
if (!Number.isInteger(len) || len <= 0) {
throw new Error('randomBytes: length must be a positive integer');
}
return (0, utils_1.randomBytes)(len);
}
/**
* Converts a Uint8Array to a bigint.
* @param bytes - Byte array to convert.
* @param littleEndian - Whether to interpret bytes in little-endian order. Default is false.
* @returns bigint representation of bytes.
*/
function bytesToInteger(bytes, littleEndian = false) {
// if little-endian, reverse into a new array
const data = littleEndian
? bytes.slice().reverse()
: bytes;
return data.reduce((acc, b) => (acc << BigInt(8)) + BigInt(b), BigInt(0));
}
/**
* Ensures the input is a string.
* @param data - Input as a string or Uint8Array.
* @returns Input converted to string.
* @throws TypeError if input is neither string nor Uint8Array.
*/
function ensureString(data) {
if (data instanceof Uint8Array) {
return new TextDecoder().decode(data);
}
if (typeof data === 'string') {
return data;
}
throw new exceptions_1.TypeError('Invalid value for string');
}
/**
* Converts a string or Uint8Array to a bigint.
* @param data - Input string (hex) or Uint8Array.
* @returns bigint representation of input.
*/
function stringToInteger(data) {
let buf;
if (typeof data === 'string') {
// treat string as hex (even-length hex string)
buf = hexToBytes(data);
}
else {
buf = data;
}
let val = BigInt(0);
for (let i = 0; i < buf.length; i++) {
val = (val << BigInt(8)) + BigInt(buf[i]);
}
return val;
}
/**
* Compares two Uint8Arrays for equality.
* @param a - First array.
* @param b - Second array.
* @returns true if arrays are equal, false otherwise.
*/
function equalBytes(a, b) {
if (a.length !== b.length)
return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i])
return false;
}
return true;
}
/**
* Converts a bigint or number to a Uint8Array.
* @param value - Value to convert.
* @param length - Optional fixed byte length for output.
* @param endianness - 'big' or 'little' endian. Default is 'big'.
* @returns Uint8Array representing the integer.
*/
function integerToBytes(value, length, endianness = 'big') {
// coerce to BigInt without using 0n
let val = typeof value === 'number' ? BigInt(value) : value;
if (val < BigInt(0)) {
throw new Error(`Cannot convert negative integers: ${val}`);
}
// build big-endian array
const bytes = [];
const ZERO = BigInt(0);
const SHIFT = BigInt(8);
const MASK = BigInt(0xff);
while (val > ZERO) {
// val & 0xffn → val & MASK
bytes.unshift(Number(val & MASK));
// val >>= 8n → val = val >> SHIFT
val = val >> SHIFT;
}
if (bytes.length === 0) {
bytes.push(0);
}
// pad/truncate
if (length !== undefined) {
if (bytes.length > length) {
throw new Error(`Integer too large to fit in ${length} bytes`);
}
while (bytes.length < length) {
bytes.unshift(0);
}
}
const result = new Uint8Array(bytes);
return endianness === 'little' ? result.reverse() : result;
}
/**
* Concatenates multiple Uint8Arrays.
* @param chunks - Arrays to concatenate.
* @returns Concatenated Uint8Array.
*/
function concatBytes(...chunks) {
const totalLength = chunks.reduce((sum, arr) => sum + arr.length, 0);
const result = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
result.set(chunk, offset);
offset += chunk.length;
}
return result;
}
/**
* Converts bytes to a binary string.
* @param data - Input bytes.
* @param zeroPadBits - Optional zero-padding to reach a specific bit length.
* @returns Binary string representation of bytes.
*/
function bytesToBinaryString(data, zeroPadBits = 0) {
const bits = Array.from(data)
.map((b) => b.toString(2).padStart(8, '0'))
.join('');
return bits.length < zeroPadBits ? bits.padStart(zeroPadBits, '0') : bits;
}
/**
* Converts a binary string or bytes to a bigint.
* @param data - Binary string or Uint8Array.
* @returns bigint representation.
*/
function binaryStringToInteger(data) {
const bin = typeof data === 'string'
? data
: bytesToBinaryString(data);
const clean = bin.trim();
return BigInt('0b' + clean);
}
/**
* Converts an integer to a binary string.
* @param data - Input number or bigint.
* @param zeroPadBits - Optional zero-padding to reach a specific bit length.
* @returns Binary string.
*/
function integerToBinaryString(data, zeroPadBits = 0) {
const big = typeof data === 'bigint' ? data : BigInt(data);
const bits = big.toString(2);
return bits.length < zeroPadBits
? bits.padStart(zeroPadBits, '0')
: bits;
}
/**
* Converts a binary string or Uint8Array to bytes.
* @param data - Input binary string or bytes.
* @param zeroPadByteLen - Optional zero-padding to reach a specific byte length.
* @returns Uint8Array representation.
*/
function binaryStringToBytes(data, zeroPadByteLen = 0) {
const bits = typeof data === 'string'
? data.trim()
: bytesToBinaryString(data);
const bitLen = bits.length;
const val = BigInt('0b' + bits);
let hex = val.toString(16);
if (hex.length % 2 === 1) {
hex = '0' + hex;
}
const byteLen = zeroPadByteLen > 0
? zeroPadByteLen
: Math.ceil(bitLen / 8);
const expectedHexLen = byteLen * 2;
if (hex.length < expectedHexLen) {
hex = hex.padStart(expectedHexLen, '0');
}
return hexToBytes(hex);
}
/**
* Checks if all inputs are equal.
* @param inputs - Inputs of various types to compare.
* @returns true if all inputs are equal, false otherwise.
*/
function isAllEqual(...inputs) {
if (inputs.length < 2)
return true;
const getTag = (v) => {
if (typeof v === 'string')
return 'string';
if (typeof v === 'number')
return 'number';
if (typeof v === 'boolean')
return 'boolean';
if (Array.isArray(v)) {
if (v.every(i => typeof i === 'number'))
return 'array:number';
if (v.every(i => typeof i === 'string'))
return 'array:string';
if (v.every(i => typeof i === 'boolean'))
return 'array:boolean';
return 'array:unknown';
}
if (v instanceof Uint8Array)
return 'uint8array';
if (v instanceof ArrayBuffer)
return 'arraybuffer';
if (ArrayBuffer.isView(v))
return 'view';
return 'unknown';
};
const firstTag = getTag(inputs[0]);
if (firstTag === 'unknown' || firstTag === 'array:unknown')
return false;
for (const v of inputs.slice(1)) {
if (getTag(v) !== firstTag)
return false;
}
if (firstTag === 'string' || firstTag === 'number' || firstTag === 'boolean') {
const first = inputs[0];
return inputs.every(v => v === first);
}
if (firstTag.startsWith('array:')) {
const firstArr = inputs[0];
const len = firstArr.length;
return inputs.slice(1).every(item => {
const arr = item;
if (arr.length !== len)
return false;
for (let i = 0; i < len; i++) {
if (arr[i] !== firstArr[i])
return false;
}
return true;
});
}
const normalize = (v) => {
if (v instanceof Uint8Array)
return v;
if (v instanceof ArrayBuffer)
return new Uint8Array(v);
return new Uint8Array(v.buffer, v.byteOffset, v.byteLength);
};
const firstArr = normalize(inputs[0]);
const len = firstArr.byteLength;
return inputs.slice(1).every(item => {
const arr = normalize(item);
if (arr.byteLength !== len)
return false;
for (let i = 0; i < len; i++) {
if (arr[i] !== firstArr[i])
return false;
}
return true;
});
}
/**
* Generates a random alphanumeric passphrase.
* @param length - Length of the passphrase. Default is 32.
* @param chars - Characters to use. Default is alphanumeric.
* @returns Randomly generated passphrase string.
*/
function generatePassphrase(length = 32, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
const bytes = randomBytes(length);
let result = '';
for (let i = 0; i < length; i++) {
result += chars[bytes[i] % chars.length];
}
return result;
}
/**
* Returns HMAC seed based on ECC name.
* @param eccName - ECC curve name.
* @returns Seed as Uint8Array.
* @throws DerivationError if curve is unknown.
*/
function getHmac(eccName) {
const encoder = new TextEncoder();
if ([
'Kholaw-Ed25519', 'SLIP10-Ed25519', 'SLIP10-Ed25519-Blake2b', 'SLIP10-Ed25519-Monero',
].includes(eccName)) {
return encoder.encode('ed25519 seed');
}
else if (eccName === 'SLIP10-Nist256p1') {
return encoder.encode('Nist256p1 seed');
}
else if (eccName === 'SLIP10-Secp256k1') {
return encoder.encode('Bitcoin seed');
}
throw new exceptions_1.DerivationError('Unknown ECC name');
}
/**
* Excludes specific keys from nested objects recursively.
* @param nested - Input object.
* @param keys - Keys to exclude.
* @returns New object excluding specified keys.
*/
function excludeKeys(nested, keys) {
const out = {};
const keySet = new Set(keys); // optional optimization
for (const [k, v] of Object.entries(nested)) {
const normKey = k.replace(/-/g, '_');
if (keySet.has(normKey))
continue;
if (v &&
typeof v === 'object' &&
!Array.isArray(v) &&
!(v instanceof Uint8Array) &&
!(v instanceof Uint8Array)) {
out[k] = excludeKeys(v, keys);
}
else {
out[k] = v;
}
}
return out;
}
/**
* Converts derivation path string to an array of indexes.
* @param path - Derivation path (e.g., "m/44'/0'/0'").
* @returns Array of numeric indexes.
* @throws DerivationError on invalid path.
*/
function pathToIndexes(path) {
if (path === 'm' || path === 'm/')
return [];
if (!path.startsWith('m/')) {
throw new exceptions_1.DerivationError(`Bad path format, expected 'm/0'/0', got '${path}'`);
}
return path
.slice(2)
.split('/')
.map(i => i.endsWith("'")
? parseInt(i.slice(0, -1), 10) + 0x80000000
: parseInt(i, 10));
}
/**
* Converts array of indexes to a derivation path string.
* @param indexes - Array of numeric indexes.
* @returns Derivation path string.
*/
function indexesToPath(indexes) {
return ('m' +
indexes
.map(i => i & 0x80000000
? `/${(i & ~0x80000000).toString()}'`
: `/${i.toString()}`)
.join(''));
}
/**
* Normalize a BIP32 derivation index to a tuple.
* @param index - Index as number, string (e.g., "0" or "0-3"), or tuple [from, to].
* @param hardened - Whether the index is hardened (default: false)
* @returns Normalized derivation tuple.
* @throws DerivationError on invalid input.
*/
function normalizeIndex(index, hardened = false) {
if (typeof index === 'number') {
if (index < 0)
throw new exceptions_1.DerivationError(`Bad index: ${index}`);
return [index, hardened];
}
if (typeof index === 'string') {
const m = index.match(/^(\d+)(?:-(\d+))?$/);
if (!m) {
throw new exceptions_1.DerivationError(`Bad index format, got '${index}'`);
}
const from = parseInt(m[1], 10);
const to = m[2] ? parseInt(m[2], 10) : undefined;
if (to === undefined)
return [from, hardened];
if (from > to) {
throw new exceptions_1.DerivationError(`Range start ${from} > end ${to}`);
}
return [from, to, hardened];
}
if (Array.isArray(index)) {
const [a, b] = index;
if (index.length !== 2 || typeof a !== 'number' || typeof b !== 'number') {
throw new exceptions_1.DerivationError(`Bad index tuple: ${JSON.stringify(index)}`);
}
if (a < 0 || b < 0) {
throw new exceptions_1.DerivationError(`Negative in tuple: ${index}`);
}
if (a > b) {
throw new exceptions_1.DerivationError(`Range start ${a} > end ${b}`);
}
return [a, b, hardened];
}
throw new exceptions_1.DerivationError(`Invalid index instance, got ${typeof index}`);
}
/**
* Normalize a derivation path string or numeric indexes.
* @param path - Optional path string like "m/0'/1-3'"
* @param indexes - Optional array of numeric indexes
* @returns Tuple: [normalized path string, indexes array, derivation tuples]
* @throws DerivationError on invalid input
*/
function normalizeDerivation(path, indexes) {
let _path = 'm';
const _indexes = [];
const _deriv = [];
if (indexes && path) {
throw new exceptions_1.DerivationError('Provide either path or indexes, not both');
}
if (indexes) {
path = indexesToPath(indexes);
}
if (!path || path === 'm' || path === 'm/') {
return [`${_path}/`, _indexes, _deriv];
}
if (!path.startsWith('m/')) {
throw new exceptions_1.DerivationError(`Bad path format, got '${path}'`);
}
for (const seg of path.slice(2).split('/')) {
const hardened = seg.endsWith("'");
const core = hardened ? seg.slice(0, -1) : seg;
const parts = core.split('-').map(x => parseInt(x, 10));
if (parts.length === 2) {
const [from, to] = parts;
if (from > to) {
throw new exceptions_1.DerivationError(`Range start ${from} > end ${to}`);
}
_deriv.push([from, to, hardened]);
_indexes.push(to + (hardened ? 0x80000000 : 0));
_path += hardened ? `/${to}'` : `/${to}`;
}
else {
const idx = parts[0];
_deriv.push([idx, hardened]);
_indexes.push(idx + (hardened ? 0x80000000 : 0));
_path += hardened ? `/${idx}'` : `/${idx}`;
}
}
return [_path, _indexes, _deriv];
}
/**
* Convert a derivation tuple to integer representation
* @param idx - Derivation tuple [index, hardened] or [from, to, hardened]
* @returns Integer value with hardened bit applied if necessary
*/
function indexTupleToInteger(idx) {
if (idx.length === 2) {
const [i, h] = idx;
return i + (h ? 0x80000000 : 0);
}
else {
const [from, to, h] = idx;
return to + (h ? 0x80000000 : 0);
}
}
/**
* Convert a derivation tuple to a string representation
* @param idx - Derivation tuple [index, hardened] or [from, to, hardened]
* @returns String like "0'" or "0-3'"
*/
function indexTupleToString(idx) {
if (idx.length === 2) {
const [i, h] = idx;
return `${i}${h ? "'" : ''}`;
}
else {
const [from, to, h] = idx;
return `${from}-${to}${h ? "'" : ''}`;
}
}
/**
* Convert a single index string "0'" into tuple [0, true]
* @param i - Index string
* @returns Tuple [index number, hardened boolean]
*/
function indexStringToTuple(i) {
const hardened = i.endsWith("'");
const num = parseInt(hardened ? i.slice(0, -1) : i, 10);
return [num, hardened];
}
/**
* XOR two Uint8Arrays of equal length
* @param a - First byte array
* @param b - Second byte array
* @returns New Uint8Array resulting from XOR
* @throws DerivationError if lengths mismatch
*/
function xor(a, b) {
if (a.length !== b.length)
throw new exceptions_1.DerivationError('Uint8Arrays must match length for XOR');
return getBytes(a.map((x, i) => x ^ b[i]));
}
/**
* Add two Uint8Arrays element-wise modulo 256
* @param a - First byte array
* @param b - Second byte array
* @returns New Uint8Array result
* @throws DerivationError if lengths mismatch
*/
function addNoCarry(a, b) {
if (a.length !== b.length)
throw new exceptions_1.DerivationError('Uint8Arrays must match length for addNoCarry');
return getBytes(a.map((x, i) => (x + b[i]) & 0xff));
}
/**
* Multiply each byte by a scalar modulo 256
* @param data - Byte array
* @param scalar - Integer scalar
* @returns New Uint8Array result
*/
function multiplyScalarNoCarry(data, scalar) {
return getBytes(data.map(x => (x * scalar) & 0xff));
}
/** Bit manipulation helpers */
function isBitsSet(value, bitNum) {
return (value & (1 << bitNum)) !== 0;
}
function areBitsSet(value, mask) {
return (value & mask) !== 0;
}
function setBit(value, bitNum) {
return value | (1 << bitNum);
}
function setBits(value, mask) {
return value | mask;
}
function resetBit(value, bitNum) {
return value & ~(1 << bitNum);
}
function resetBits(value, mask) {
return value & ~mask;
}
/**
* Reverse a Uint8Array
* @param data - Byte array
* @returns New Uint8Array reversed
*/
function bytesReverse(data) {
return getBytes(data).reverse();
}
/**
* Convert bits between different widths
* @param data - Array of numbers or Uint8Array
* @param fromBits - Original bit width
* @param toBits - Target bit width
* @returns Array of converted bits or null if input invalid
*/
function convertBits(data, fromBits, toBits) {
const input = Array.isArray(data) ? data : Array.from(data);
const maxVal = (1 << toBits) - 1;
let acc = 0;
let bits = 0;
const out = [];
for (const val of input) {
if (val < 0 || val >> fromBits) {
return null;
}
acc |= val << bits;
bits += fromBits;
while (bits >= toBits) {
out.push(acc & maxVal);
acc >>= toBits;
bits -= toBits;
}
}
if (bits > 0) {
out.push(acc & maxVal);
}
return out;
}
/**
* Convert a byte chunk to mnemonic words
* @param bytesChunk - Uint8Array of bytes
* @param wordsList - Wordlist array
* @param endianness - "little" or "big"
* @returns Tuple of 3 mnemonic words
*/
function bytesChunkToWords(bytesChunk, wordsList, endianness) {
const len = BigInt(wordsList.length);
let chunkNum = bytesToInteger(new Uint8Array(bytesChunk), endianness !== 'big');
const i1 = Number(chunkNum % len);
const i2 = Number(((chunkNum / len) + BigInt(i1)) % len);
const i3 = Number(((chunkNum / len / len) + BigInt(i2)) % len);
return [wordsList[i1], wordsList[i2], wordsList[i3]];
}
/**
* Convert 3 mnemonic words to a byte chunk
* @param w1 - Word 1
* @param w2 - Word 2
* @param w3 - Word 3
* @param wordsList - Wordlist array
* @param endianness - "little" or "big"
* @returns Uint8Array of bytes
*/
function wordsToBytesChunk(w1, w2, w3, wordsList, endianness) {
const len = BigInt(wordsList.length);
const idxMap = new Map(wordsList.map((w, i) => [w, BigInt(i)]));
const i1 = idxMap.get(w1);
const i2 = idxMap.get(w2);
const i3 = idxMap.get(w3);
const chunk = i1 + len * ((i2 - i1 + len) % len) + len * len * ((i3 - i2 + len) % len);
const u8 = integerToBytes(chunk, 4, endianness);
return getBytes(u8);
}
/**
* Convert kebab-case string to camelCase
* @param input - Input string
* @returns CamelCase string
*/
function toCamelCase(input) {
return input.toLowerCase().replace(/-([a-z])/g, (_, char) => char.toUpperCase());
}
/**
* Ensure a value matches the expected type(s)
* @param instanceOrClass - Value or class instance
* @param expectedType - Expected type or constructor
* @param options - Optional object with otherTypes, strict, errorClass
* @returns Value or object with {value, isValid}
* @throws TypeError or custom error if type mismatch
*/
function ensureTypeMatch(instanceOrClass, expectedType, options = {}) {
const tryMatch = (type) => {
if (type === 'any')
return true;
if (type === 'null')
return instanceOrClass === null;
if (type === 'array')
return Array.isArray(instanceOrClass);
if (typeof type === 'string')
return typeof instanceOrClass === type;
if (typeof type === 'function') {
if (typeof instanceOrClass === 'function') {
let proto = instanceOrClass;
while (proto && proto !== Function.prototype) {
if (proto === type)
return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}
return options.strict
? instanceOrClass?.constructor === type
: instanceOrClass instanceof type;
}
return false;
};
const allExpectedTypes = [expectedType, ...(options.otherTypes || [])];
const matched = allExpectedTypes.find(tryMatch);
if (!matched && (options.errorClass || options.otherTypes)) {
const expectedNames = allExpectedTypes.map((type) => typeof type === 'function' ? type.name : String(type));
const gotName = typeof instanceOrClass === 'function'
? instanceOrClass.name
: instanceOrClass?.constructor?.name ?? typeof instanceOrClass;
if (options.errorClass) {
throw new options.errorClass(`Invalid type`, {
expected: expectedNames, got: gotName
});
}
else {
throw new exceptions_1.TypeError(`Invalid type`, {
expected: expectedNames, got: gotName
});
}
}
return matched && options.errorClass ? instanceOrClass : {
value: instanceOrClass, isValid: tryMatch(expectedType)
};
}
//# sourceMappingURL=utils.js.map