UNPKG

@neuraiproject/neurai-key

Version:

Generate Neurai addresses from mnemonic code. BIP32, BIP39, BIP44

930 lines (921 loc) 35.3 kB
import { validateMnemonic, generateMnemonic as generateMnemonic$1, entropyToMnemonic as entropyToMnemonic$1, mnemonicToSeedSync } from '@scure/bip39'; import { wordlist } from '@scure/bip39/wordlists/czech.js'; import { wordlist as wordlist$1 } from '@scure/bip39/wordlists/english.js'; import { wordlist as wordlist$3 } from '@scure/bip39/wordlists/french.js'; import { wordlist as wordlist$4 } from '@scure/bip39/wordlists/italian.js'; import { wordlist as wordlist$5 } from '@scure/bip39/wordlists/japanese.js'; import { wordlist as wordlist$6 } from '@scure/bip39/wordlists/korean.js'; import { wordlist as wordlist$7 } from '@scure/bip39/wordlists/portuguese.js'; import { wordlist as wordlist$2 } from '@scure/bip39/wordlists/spanish.js'; import { wordlist as wordlist$8 } from '@scure/bip39/wordlists/simplified-chinese.js'; import { ripemd160 } from '@noble/hashes/legacy.js'; import { hmac } from '@noble/hashes/hmac.js'; import { sha512, sha256 } from '@noble/hashes/sha2.js'; import { utf8ToBytes, concatBytes as concatBytes$1, bytesToHex as bytesToHex$1, hexToBytes as hexToBytes$1 } from '@noble/hashes/utils.js'; import { secp256k1 } from '@noble/curves/secp256k1.js'; import { bech32m } from 'bech32'; import { ml_dsa44 } from '@noble/post-quantum/ml-dsa.js'; /*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */ function isBytes(a) { // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases. The // fallback still requires a real ArrayBuffer view, so plain JSON-deserialized // `{ constructor: ... }` spoofing is rejected. `BYTES_PER_ELEMENT === 1` keeps the // fallback on byte-oriented views. return (a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array' && 'BYTES_PER_ELEMENT' in a && a.BYTES_PER_ELEMENT === 1)); } function isArrayOf(isString, arr) { if (!Array.isArray(arr)) return false; if (arr.length === 0) return true; if (isString) { return arr.every((item) => typeof item === 'string'); } else { return arr.every((item) => Number.isSafeInteger(item)); } } function astr(label, input) { if (typeof input !== 'string') throw new TypeError(`${label}: string expected`); return true; } function anumber(n) { if (typeof n !== 'number') throw new TypeError(`number expected, got ${typeof n}`); if (!Number.isSafeInteger(n)) throw new RangeError(`invalid integer: ${n}`); } function aArr(input) { if (!Array.isArray(input)) throw new TypeError('array expected'); } function astrArr(label, input) { if (!isArrayOf(true, input)) throw new TypeError(`${label}: array of strings expected`); } function anumArr(label, input) { if (!isArrayOf(false, input)) throw new TypeError(`${label}: array of numbers expected`); } /** * @__NO_SIDE_EFFECTS__ */ function chain(...args) { const id = (a) => a; // Wrap call in closure so JIT can inline calls const wrap = (a, b) => (c) => a(b(c)); // Construct chain of args[-1].encode(args[-2].encode([...])) const encode = args.map((x) => x.encode).reduceRight(wrap, id); // Construct chain of args[0].decode(args[1].decode(...)) const decode = args.map((x) => x.decode).reduce(wrap, id); return { encode, decode }; } /** * Encodes integer radix representation to array of strings using alphabet and back. * Could also be array of strings. * @__NO_SIDE_EFFECTS__ */ function alphabet(letters) { // mapping 1 to "b" const lettersA = typeof letters === 'string' ? letters.split('') : letters; const len = lettersA.length; astrArr('alphabet', lettersA); // mapping "b" to 1 const indexes = new Map(lettersA.map((l, i) => [l, i])); return { encode: (digits) => { aArr(digits); return digits.map((i) => { if (!Number.isSafeInteger(i) || i < 0 || i >= len) throw new Error(`alphabet.encode: digit index outside alphabet "${i}". Allowed: ${letters}`); return lettersA[i]; }); }, decode: (input) => { aArr(input); return input.map((letter) => { astr('alphabet.decode', letter); const i = indexes.get(letter); if (i === undefined) throw new Error(`Unknown letter: "${letter}". Allowed: ${letters}`); return i; }); }, }; } /** * @__NO_SIDE_EFFECTS__ */ function join(separator = '') { astr('join', separator); // join('') is only lossless when each chunk is already unambiguous, such as single-symbol alphabets. // Multi-character tokens need a separator that cannot appear inside the chunks. return { encode: (from) => { astrArr('join.decode', from); return from.join(separator); }, decode: (to) => { astr('join.decode', to); return to.split(separator); }, }; } /** * Slow: O(n^2) time complexity */ function convertRadix(data, from, to) { // base 1 is impossible if (from < 2) throw new RangeError(`convertRadix: invalid from=${from}, base cannot be less than 2`); if (to < 2) throw new RangeError(`convertRadix: invalid to=${to}, base cannot be less than 2`); aArr(data); if (!data.length) return []; let pos = 0; const res = []; const digits = Array.from(data, (d) => { anumber(d); if (d < 0 || d >= from) throw new Error(`invalid integer: ${d}`); return d; }); const dlen = digits.length; while (true) { let carry = 0; let done = true; for (let i = pos; i < dlen; i++) { const digit = digits[i]; const fromCarry = from * carry; const digitBase = fromCarry + digit; if (!Number.isSafeInteger(digitBase) || fromCarry / from !== carry || digitBase - digit !== fromCarry) { throw new Error('convertRadix: carry overflow'); } const div = digitBase / to; carry = digitBase % to; const rounded = Math.floor(div); digits[i] = rounded; if (!Number.isSafeInteger(rounded) || rounded * to + carry !== digitBase) throw new Error('convertRadix: carry overflow'); if (!done) continue; else if (!rounded) pos = i; else done = false; } res.push(carry); if (done) break; } // Preserve explicit leading zero digits so callers like base58 keep zero-prefix semantics. for (let i = 0; i < data.length - 1 && data[i] === 0; i++) res.push(0); return res.reverse(); } /** * @__NO_SIDE_EFFECTS__ */ function radix(num) { anumber(num); const _256 = 2 ** 8; // Base-range and carry-overflow checks live in convertRadix so encode/decode reject unsupported bases symmetrically. return { encode: (bytes) => { if (!isBytes(bytes)) throw new TypeError('radix.encode input should be Uint8Array'); return convertRadix(Array.from(bytes), _256, num); }, decode: (digits) => { anumArr('radix.decode', digits); return Uint8Array.from(convertRadix(digits, num, _256)); }, }; } // base58 code // ----------- const genBase58 = /* @__NO_SIDE_EFFECTS__ */ (abc) => chain(radix(58), alphabet(abc), join('')); /** * base58: base64 without ambigous characters +, /, 0, O, I, l. * Quadratic (O(n^2)) - so, can't be used on large inputs. * @example * ```js * const text = base58.encode(Uint8Array.from([0, 1, 2])); * base58.decode(text); * // => Uint8Array.from([0, 1, 2]) * ``` */ const base58 = /* @__PURE__ */ Object.freeze(genBase58('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz')); const HARDENED_OFFSET = 0x80000000; const SECP256K1_ORDER = BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); function bytesToHex(bytes) { return bytesToHex$1(bytes); } function concatBytes(...arrays) { return concatBytes$1(...arrays); } function hexToBytes(hex) { return hexToBytes$1(hex); } function ensureBytes(input) { return typeof input === "string" ? hexToBytes(input) : Uint8Array.from(input); } function numberToBytesBE(value, length) { const bytes = new Uint8Array(length); let current = value; for (let index = length - 1; index >= 0; index -= 1) { bytes[index] = Number(current & 0xffn); current >>= 8n; } return bytes; } function bytesToNumberBE(bytes) { let value = 0n; for (const byte of bytes) { value = (value << 8n) + BigInt(byte); } return value; } function uint32ToBytesBE(value) { const bytes = new Uint8Array(4); const view = new DataView(bytes.buffer); view.setUint32(0, value, false); return bytes; } function hash160(data) { return ripemd160(sha256(data)); } function sha256Hash(data) { return sha256(data); } function taggedHash(tag, data) { const tagHash = sha256(utf8ToBytes(tag)); return sha256(concatBytes(tagHash, tagHash, data)); } function doubleSha256(data) { return sha256(sha256(data)); } function hmacSha512(key, data) { return hmac(sha512, key, data); } function base58CheckEncode(payload) { const checksum = doubleSha256(payload).slice(0, 4); return base58.encode(concatBytes(payload, checksum)); } function base58CheckDecode(value) { const decoded = Uint8Array.from(base58.decode(value)); if (decoded.length < 5) { throw new Error("Invalid Base58Check payload"); } const payload = decoded.slice(0, -4); const checksum = decoded.slice(-4); const expected = doubleSha256(payload).slice(0, 4); for (let index = 0; index < 4; index += 1) { if (checksum[index] !== expected[index]) { throw new Error("Invalid Base58Check checksum"); } } return payload; } function bigIntMod(value, modulo) { const remainder = value % modulo; return remainder >= 0n ? remainder : remainder + modulo; } function isValidPrivateKey(privateKey) { if (privateKey.length !== 32) { return false; } const value = bytesToNumberBE(privateKey); return value > 0n && value < SECP256K1_ORDER; } function mnemonicToSeedBytes(mnemonicToSeedSync, mnemonic, passphrase) { return Uint8Array.from(mnemonicToSeedSync(mnemonic, passphrase)); } const BITCOIN_SEED_KEY = utf8ToBytes("Bitcoin seed"); const AUTHSCRIPT_TAG = "NeuraiAuthScript"; const AUTHSCRIPT_VERSION = 0x01; const NOAUTH_TYPE = 0x00; const PQ_AUTH_TYPE = 0x01; const LEGACY_AUTH_TYPE = 0x02; const PQ_PUBLIC_KEY_HEADER$1 = Uint8Array.from([0x05]); const DEFAULT_WITNESS_SCRIPT = Uint8Array.from([0x51]); function encodeWIF(privateKey, version, compressed = true) { const payload = compressed ? concatBytes(Uint8Array.from([version]), privateKey, Uint8Array.from([0x01])) : concatBytes(Uint8Array.from([version]), privateKey); return base58CheckEncode(payload); } function decodeWIF(wif) { const payload = base58CheckDecode(wif); if (payload.length !== 33 && payload.length !== 34) { throw new Error("Invalid WIF length"); } const version = payload[0]; const compressed = payload.length === 34; if (compressed && payload[payload.length - 1] !== 0x01) { throw new Error("Invalid compressed WIF payload"); } return { version, privateKey: payload.slice(1, 33), compressed, }; } function getCompressedPublicKey(privateKey) { return secp256k1.getPublicKey(privateKey, true); } function publicKeyToAddressBytes(publicKey, versions) { return base58CheckEncode(concatBytes(Uint8Array.from([versions.public]), hash160(publicKey))); } function privateKeyToAddressObject(privateKey, versions, path) { const publicKey = getCompressedPublicKey(privateKey); return { address: publicKeyToAddressBytes(publicKey, versions), path, publicKey: bytesToHex(publicKey), privateKey: bytesToHex(privateKey), WIF: encodeWIF(privateKey, versions.private), }; } function addressObjectFromWIF(wif, versions) { const decoded = decodeWIF(wif); const publicKey = decoded.compressed ? secp256k1.getPublicKey(decoded.privateKey, true) : secp256k1.getPublicKey(decoded.privateKey, false); return { address: publicKeyToAddressBytes(publicKey, versions), privateKey: bytesToHex(decoded.privateKey), WIF: encodeWIF(decoded.privateKey, versions.private, decoded.compressed), }; } function publicKeyHexFromWIF(wif, compressed = true) { const decoded = decodeWIF(wif); return bytesToHex(secp256k1.getPublicKey(decoded.privateKey, compressed && decoded.compressed)); } function bech32mEncode(hrp, witnessVersion, hash) { return bech32m.encode(hrp, [witnessVersion, ...bech32m.toWords(hash)]); } function normalizeWitnessScript(input) { return input ? ensureBytes(input) : Uint8Array.from(DEFAULT_WITNESS_SCRIPT); } function buildAuthDescriptor(authType, publicKey) { if (authType === NOAUTH_TYPE) { return Uint8Array.from([NOAUTH_TYPE]); } if (!publicKey) { throw new Error(`Auth type 0x${authType.toString(16).padStart(2, "0")} requires a public key`); } if (authType === PQ_AUTH_TYPE) { return concatBytes(Uint8Array.from([PQ_AUTH_TYPE]), hash160(concatBytes(PQ_PUBLIC_KEY_HEADER$1, publicKey))); } if (authType === LEGACY_AUTH_TYPE) { return concatBytes(Uint8Array.from([LEGACY_AUTH_TYPE]), hash160(publicKey)); } throw new Error(`Unsupported authType: 0x${String(authType).padStart(2, "0")}`); } function pqPublicKeyToAuthDescriptor(publicKey) { return buildAuthDescriptor(PQ_AUTH_TYPE, publicKey); } function pqPublicKeyToCommitment(publicKey, options = {}) { return pqPublicKeyToCommitmentParts(publicKey, options).commitment; } function authScriptCommitmentParts(authType, publicKey, options = {}) { const witnessScript = normalizeWitnessScript(options.witnessScript); const authDescriptor = buildAuthDescriptor(authType, publicKey); const witnessScriptHash = sha256Hash(witnessScript); const commitment = taggedHash(AUTHSCRIPT_TAG, concatBytes(Uint8Array.from([AUTHSCRIPT_VERSION]), authDescriptor, witnessScriptHash)); return { authDescriptor, authType, commitment, witnessScript, }; } function pqPublicKeyToCommitmentParts(publicKey, options = {}) { return authScriptCommitmentParts(PQ_AUTH_TYPE, publicKey, options); } function pqPublicKeyToAddressBytes(publicKey, network, options = {}) { return bech32mEncode(network.hrp, network.witnessVersion, pqPublicKeyToCommitment(publicKey, options)); } function noAuthToAddressBytes(network, options = {}) { return bech32mEncode(network.hrp, network.witnessVersion, authScriptCommitmentParts(NOAUTH_TYPE, null, options).commitment); } function legacyAuthScriptToAddressBytes(publicKey, network, options = {}) { return bech32mEncode(network.hrp, network.witnessVersion, authScriptCommitmentParts(LEGACY_AUTH_TYPE, publicKey, options).commitment); } function normalizePublicKey(input) { return ensureBytes(input); } function ensureValidTweak(tweak) { const tweakValue = bytesToNumberBE(tweak); if (tweakValue === 0n || tweakValue >= SECP256K1_ORDER) { throw new Error("Invalid BIP32 tweak"); } return tweakValue; } function serializeExtendedKey(version, depth, parentFingerprint, index, chainCode, keyData) { return concatBytes(uint32ToBytesBE(version), Uint8Array.from([depth]), uint32ToBytesBE(parentFingerprint), uint32ToBytesBE(index), chainCode, keyData); } class HDKey { constructor(versions, chainCode, publicKey, privateKey, depth = 0, index = 0, parentFingerprint = 0) { this.versions = versions; this.depth = depth; this.index = index; this.chainCode = chainCode; this.parentFingerprint = parentFingerprint; this.privateKey = privateKey; this.publicKey = publicKey; } static fromMasterSeed(seed, versions) { const I = hmacSha512(BITCOIN_SEED_KEY, seed); const IL = I.slice(0, 32); const IR = I.slice(32); if (!isValidPrivateKey(IL)) { throw new Error("Invalid master seed"); } const publicKey = secp256k1.getPublicKey(IL, true); return new HDKey(versions, IR, publicKey, IL); } get fingerprint() { return new DataView(hash160(this.publicKey).buffer, hash160(this.publicKey).byteOffset, 4).getUint32(0, false); } get privateExtendedKey() { if (!this.privateKey) { return null; } const keyData = concatBytes(Uint8Array.from([0x00]), this.privateKey); return base58CheckEncode(serializeExtendedKey(this.versions.private, this.depth, this.parentFingerprint, this.index, this.chainCode, keyData)); } get publicExtendedKey() { return base58CheckEncode(serializeExtendedKey(this.versions.public, this.depth, this.parentFingerprint, this.index, this.chainCode, this.publicKey)); } derive(path) { if (path === "m" || path === "M" || path === "m'" || path === "M'") { return this; } const entries = path.split("/"); let current = this; entries.forEach((entry, index) => { if (index === 0) { if (!/^[mM]{1}/.test(entry)) { throw new Error('Path must start with "m" or "M"'); } return; } const hardened = entry.endsWith("'"); const childIndex = Number.parseInt(entry, 10); if (!Number.isFinite(childIndex) || childIndex >= HARDENED_OFFSET) { throw new Error("Invalid index"); } current = current.deriveChild(hardened ? childIndex + HARDENED_OFFSET : childIndex); }); return current; } deriveChild(index) { const hardened = index >= HARDENED_OFFSET; const indexBytes = uint32ToBytesBE(index); const data = hardened ? (() => { if (!this.privateKey) { throw new Error("Could not derive hardened child key"); } return concatBytes(Uint8Array.from([0x00]), this.privateKey, indexBytes); })() : concatBytes(this.publicKey, indexBytes); const I = hmacSha512(this.chainCode, data); const IL = I.slice(0, 32); const IR = I.slice(32); let tweak; try { tweak = ensureValidTweak(IL); } catch { return this.deriveChild(index + 1); } if (this.privateKey) { const childKey = bigIntMod(bytesToNumberBE(this.privateKey) + tweak, SECP256K1_ORDER); if (childKey === 0n) { return this.deriveChild(index + 1); } const privateKey = numberToBytesBE(childKey, 32); const publicKey = secp256k1.getPublicKey(privateKey, true); return new HDKey(this.versions, IR, publicKey, privateKey, this.depth + 1, index, this.fingerprint); } const tweakPoint = secp256k1.Point.BASE.multiply(tweak); const parentPoint = secp256k1.Point.fromHex(bytesToHex(this.publicKey)); const childPoint = tweakPoint.add(parentPoint); if (childPoint.equals(secp256k1.Point.ZERO)) { return this.deriveChild(index + 1); } return new HDKey(this.versions, IR, childPoint.toBytes(true), undefined, this.depth + 1, index, this.fingerprint); } } const PQ_SEED_KEY = utf8ToBytes("Neurai PQ seed"); const PQ_PUBLIC_KEY_HEADER = 0x05; // 74-byte layout, padded to match BIP32 xprv so base58check yields "xpqp..."/"tpqp...": // depth(1) + fingerprint(4) + child(4) + chaincode(32) + padding(1=0x00) + pq_seed(32) const BIP32_PQ_EXTKEY_SIZE = 74; class PQHDKey { constructor(depth, index, parentFingerprint, chainCode, pqSeed) { this.depth = depth; this.index = index; this.parentFingerprint = parentFingerprint; this.chainCode = chainCode; this.pqSeed = pqSeed; } static fromMasterSeed(seed) { const I = hmacSha512(PQ_SEED_KEY, seed); return new PQHDKey(0, 0, new Uint8Array(4), I.slice(32, 64), I.slice(0, 32)); } ensureKeypair() { if (!this._publicKey || !this._secretKey) { const { publicKey, secretKey } = ml_dsa44.keygen(this.pqSeed); this._publicKey = publicKey; this._secretKey = secretKey; } } get publicKey() { this.ensureKeypair(); return this._publicKey; } get secretKey() { this.ensureKeypair(); return this._secretKey; } get fingerprint() { return hash160(concatBytes(Uint8Array.from([PQ_PUBLIC_KEY_HEADER]), this.publicKey)).slice(0, 4); } deriveChild(index) { if ((index & HARDENED_OFFSET) === 0) { throw new Error("PQ-HD (NIP-022) requires hardened derivation at every level"); } const data = concatBytes(Uint8Array.from([0x00]), this.pqSeed, uint32ToBytesBE(index >>> 0)); const I = hmacSha512(this.chainCode, data); return new PQHDKey(this.depth + 1, index >>> 0, this.fingerprint, I.slice(32, 64), I.slice(0, 32)); } encode() { const out = new Uint8Array(BIP32_PQ_EXTKEY_SIZE); out[0] = this.depth & 0xff; out.set(this.parentFingerprint, 1); out[5] = (this.index >>> 24) & 0xff; out[6] = (this.index >>> 16) & 0xff; out[7] = (this.index >>> 8) & 0xff; out[8] = this.index & 0xff; out.set(this.chainCode, 9); out[41] = 0x00; // padding byte (aligns layout with BIP32 xprv) out.set(this.pqSeed, 42); return out; } encodeBase58Check(version) { const versionBytes = Uint8Array.from([ (version >>> 24) & 0xff, (version >>> 16) & 0xff, (version >>> 8) & 0xff, version & 0xff, ]); return base58CheckEncode(concatBytes(versionBytes, this.encode())); } static decode(raw, parentFingerprint) { if (raw.length !== BIP32_PQ_EXTKEY_SIZE) { throw new Error(`PQ extended key payload must be ${BIP32_PQ_EXTKEY_SIZE} bytes`); } if (raw[41] !== 0x00) { throw new Error("PQ extended key padding byte (offset 41) must be 0x00"); } const depth = raw[0]; const fingerprint = parentFingerprint ?? raw.slice(1, 5); const index = ((raw[5] << 24) | (raw[6] << 16) | (raw[7] << 8) | raw[8]) >>> 0; const chainCode = raw.slice(9, 41); const pqSeed = raw.slice(42, 74); return new PQHDKey(depth, index, Uint8Array.from(fingerprint.slice(0, 4)), chainCode, pqSeed); } static decodeBase58Check(extKey, expectedVersion) { const payload = base58CheckDecode(extKey); if (payload.length !== 4 + BIP32_PQ_EXTKEY_SIZE) { throw new Error("Invalid PQ extended key length"); } const version = ((payload[0] << 24) | (payload[1] << 16) | (payload[2] << 8) | payload[3]) >>> 0; if (version !== (expectedVersion >>> 0)) { throw new Error(`PQ extended key version mismatch (expected 0x${expectedVersion.toString(16)}, got 0x${version.toString(16)})`); } return PQHDKey.decode(payload.slice(4)); } derive(path) { const entries = path.split("/"); const root = entries[0]; if (root !== "m" && root !== "M" && root !== "m_pq" && root !== "M_pq") { throw new Error('PQ path must start with "m_pq" (or "m")'); } if (entries.length === 1) { return this; } let current = this; for (let i = 1; i < entries.length; i += 1) { const entry = entries[i]; const hardened = entry.endsWith("'"); if (!hardened) { throw new Error(`PQ-HD path requires hardened indices (got "${entry}")`); } const raw = Number.parseInt(entry.slice(0, -1), 10); if (!Number.isFinite(raw) || raw < 0 || raw >= HARDENED_OFFSET) { throw new Error(`Invalid PQ-HD index "${entry}"`); } current = current.deriveChild(raw + HARDENED_OFFSET); } return current; } } const currentNetworks = { xna: { versions: { bip32: { private: 76066276, public: 76067358 }, bip44: 1900, private: 128, public: 53, scripthash: 117, }, }, "xna-test": { versions: { bip32: { private: 70615956, public: 70617039 }, bip44: 1, private: 239, public: 127, scripthash: 196, }, }, "xna-legacy": { versions: { bip32: { private: 76066276, public: 76067358 }, bip44: 0, private: 128, public: 53, scripthash: 117, }, }, "xna-legacy-test": { versions: { bip32: { private: 70615956, public: 70617039 }, bip44: 1, private: 239, public: 127, scripthash: 196, }, }, }; const pqNetworks = { "xna-pq": { hrp: "nq", witnessVersion: 1, purpose: 100, coinType: 1900, changeIndex: 0, pqExtPrivVersion: 0x0488ac24, // "xpqp..." prefix, matches Neurai node chainparams.cpp }, "xna-pq-test": { hrp: "tnq", witnessVersion: 1, purpose: 100, coinType: 1, changeIndex: 0, pqExtPrivVersion: 0x043581d5, // "tpqp..." prefix, matches Neurai node chainparams.cpp }, }; function getNetwork(name) { const network = currentNetworks[name]; if (!network) { throw new Error(`network must be of value ${Object.keys(currentNetworks).toString()}`); } return network.versions; } function getPQNetwork(name) { const network = pqNetworks[name]; if (!network) { throw new Error("PQ network must be 'xna-pq' or 'xna-pq-test'"); } return network; } const mnemonicWordlists = [ wordlist, wordlist$1, wordlist$2, wordlist$3, wordlist$4, wordlist$5, wordlist$6, wordlist$7, wordlist$8, ]; function getCoinType(network) { return getNetwork(network).bip44; } function getAddressPair(network, mnemonic, account, position, passphrase = "") { const hdKey = getHDKey(network, mnemonic, passphrase); const coinType = getCoinType(network); const externalPath = `m/44'/${coinType}'/${account}'/0/${position}`; const internalPath = `m/44'/${coinType}'/${account}'/1/${position}`; return { internal: getAddressByPath(network, hdKey, internalPath), external: getAddressByPath(network, hdKey, externalPath), position, }; } function getHDKey(network, mnemonic, passphrase = "") { const chain = getNetwork(network); const seed = mnemonicToSeedBytes(mnemonicToSeedSync, mnemonic, passphrase); return HDKey.fromMasterSeed(seed, chain.bip32); } function getAddressByPath(network, hdKey, path) { const chain = getNetwork(network); const derived = hdKey.derive(path); if (!derived.privateKey) { throw new Error("Could not derive private key for path"); } return privateKeyToAddressObject(derived.privateKey, chain, path); } function generateMnemonic() { return generateMnemonic$1(wordlist$1); } function isMnemonicValid(mnemonic) { return mnemonicWordlists.some((wordlist) => validateMnemonic(mnemonic, wordlist)); } function getAddressByWIF(network, privateKeyWIF) { return addressObjectFromWIF(privateKeyWIF, getNetwork(network)); } function getPubkeyByWIF(_network, privateKeyWIF) { return publicKeyHexFromWIF(privateKeyWIF); } function entropyToMnemonic(entropy) { const normalized = typeof entropy === "string" ? ensureBytes(entropy) : entropy; return entropyToMnemonic$1(normalized, wordlist$1); } function generateAddressObject(network = "xna", passphrase = "") { const mnemonic = generateMnemonic(); const addressObject = getAddressPair(network, mnemonic, 0, 0, passphrase).external; return { ...addressObject, mnemonic, network, }; } function publicKeyToAddress(network, publicKey) { const keyBytes = normalizePublicKey(publicKey); if (keyBytes.length !== 33 && keyBytes.length !== 65) { throw new Error("Public key must be 33 or 65 bytes"); } return publicKeyToAddressBytes(keyBytes, getNetwork(network)); } function generateAddress(network = "xna") { return generateAddressObject(network); } function getPQHDKey(_network, mnemonic, passphrase = "") { const seed = mnemonicToSeedBytes(mnemonicToSeedSync, mnemonic, passphrase); return PQHDKey.fromMasterSeed(seed); } function pqExtendedPrivateKey(network, hdKey) { return hdKey.encodeBase58Check(getPQNetwork(network).pqExtPrivVersion); } function pqHDKeyFromExtended(network, extKey) { return PQHDKey.decodeBase58Check(extKey, getPQNetwork(network).pqExtPrivVersion); } function getPQAddressByPath(network, hdKey, path, options = {}) { const chain = getPQNetwork(network); const derived = hdKey.derive(path); const publicKey = derived.publicKey; const secretKey = derived.secretKey; const authScript = pqPublicKeyToCommitmentParts(publicKey, options); return { address: pqPublicKeyToAddressBytes(publicKey, chain, options), authType: 0x01, authDescriptor: bytesToHex(authScript.authDescriptor), commitment: bytesToHex(authScript.commitment), path, publicKey: bytesToHex(publicKey), privateKey: bytesToHex(secretKey), seedKey: bytesToHex(derived.pqSeed), witnessScript: bytesToHex(authScript.witnessScript), }; } function getNoAuthAddress(network, options = {}) { const chain = getPQNetwork(network); const parts = authScriptCommitmentParts(0x00, null, options); return { address: noAuthToAddressBytes(chain, options), authType: 0x00, commitment: bytesToHex(parts.commitment), witnessScript: bytesToHex(parts.witnessScript), }; } function getLegacyAuthScriptAddress(network, legacyNetwork, mnemonic, account, index, passphrase = "", options = {}) { const pqChain = getPQNetwork(network); const legacyChain = getNetwork(legacyNetwork); const coinType = legacyChain.bip44; const hdKey = getHDKey(legacyNetwork, mnemonic, passphrase); const path = `m/44'/${coinType}'/${account}'/0/${index}`; const derived = hdKey.derive(path); if (!derived.privateKey) { throw new Error("Could not derive private key for path"); } const legacyObject = privateKeyToAddressObject(derived.privateKey, legacyChain, path); const publicKeyBytes = ensureBytes(legacyObject.publicKey); const parts = authScriptCommitmentParts(0x02, publicKeyBytes, options); return { address: legacyAuthScriptToAddressBytes(publicKeyBytes, pqChain, options), path, publicKey: legacyObject.publicKey, privateKey: legacyObject.privateKey, WIF: legacyObject.WIF, authType: 0x02, authDescriptor: bytesToHex(parts.authDescriptor), commitment: bytesToHex(parts.commitment), witnessScript: bytesToHex(parts.witnessScript), }; } function getLegacyAuthScriptAddressByWIF(network, wif, options = {}) { const pqChain = getPQNetwork(network); const publicKeyHex = publicKeyHexFromWIF(wif); const publicKeyBytes = ensureBytes(publicKeyHex); const parts = authScriptCommitmentParts(0x02, publicKeyBytes, options); return { address: legacyAuthScriptToAddressBytes(publicKeyBytes, pqChain, options), publicKey: publicKeyHex, privateKey: "", WIF: wif, authType: 0x02, authDescriptor: bytesToHex(parts.authDescriptor), commitment: bytesToHex(parts.commitment), witnessScript: bytesToHex(parts.witnessScript), }; } function getPQAddress(network, mnemonic, account, index, passphrase = "", options = {}) { const chain = getPQNetwork(network); const hdKey = getPQHDKey(network, mnemonic, passphrase); const path = `m_pq/${chain.purpose}'/${chain.coinType}'/${account}'/${chain.changeIndex}'/${index}'`; return getPQAddressByPath(network, hdKey, path, options); } function pqPublicKeyToAddress(network, publicKey, options = {}) { const keyBytes = ensureBytes(publicKey); if (keyBytes.length !== 1312) { throw new Error("ML-DSA-44 public key must be 1312 bytes"); } normalizeWitnessScript(options.witnessScript); return pqPublicKeyToAddressBytes(keyBytes, getPQNetwork(network), options); } function pqPublicKeyToCommitmentHex(publicKey, options = {}) { const keyBytes = ensureBytes(publicKey); if (keyBytes.length !== 1312) { throw new Error("ML-DSA-44 public key must be 1312 bytes"); } return bytesToHex(pqPublicKeyToCommitment(keyBytes, options)); } function pqPublicKeyToAuthDescriptorHex(publicKey) { const keyBytes = ensureBytes(publicKey); if (keyBytes.length !== 1312) { throw new Error("ML-DSA-44 public key must be 1312 bytes"); } return bytesToHex(pqPublicKeyToAuthDescriptor(keyBytes)); } function generatePQAddressObject(network = "xna-pq", passphrase = "", options = {}) { const mnemonic = generateMnemonic(); const addressObj = getPQAddress(network, mnemonic, 0, 0, passphrase, options); return { ...addressObj, mnemonic, }; } const NeuraiKey = { entropyToMnemonic, generateAddress, generateAddressObject, generateMnemonic, getAddressByPath, getAddressByWIF, getPubkeyByWIF, getAddressPair, getCoinType, getHDKey, isMnemonicValid, publicKeyToAddress, getPQAddress, getPQAddressByPath, getPQHDKey, pqExtendedPrivateKey, pqHDKeyFromExtended, getNoAuthAddress, getLegacyAuthScriptAddress, getLegacyAuthScriptAddressByWIF, pqPublicKeyToAddress, pqPublicKeyToAuthDescriptorHex, pqPublicKeyToCommitmentHex, generatePQAddressObject, }; export { BIP32_PQ_EXTKEY_SIZE, HDKey, PQHDKey, NeuraiKey as default, entropyToMnemonic, generateAddress, generateAddressObject, generateMnemonic, generatePQAddressObject, getAddressByPath, getAddressByWIF, getAddressPair, getCoinType, getHDKey, getLegacyAuthScriptAddress, getLegacyAuthScriptAddressByWIF, getNoAuthAddress, getPQAddress, getPQAddressByPath, getPQHDKey, getPubkeyByWIF, isMnemonicValid, pqExtendedPrivateKey, pqHDKeyFromExtended, pqPublicKeyToAddress, pqPublicKeyToAuthDescriptorHex, pqPublicKeyToCommitmentHex, publicKeyToAddress }; //# sourceMappingURL=index.js.map