@neuraiproject/neurai-key 3.0.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -7,9 +7,12 @@ interface IAddressObject {
7
7
  privateKey: string;
8
8
  WIF: string;
9
9
  }
10
- interface PQAddressOptions {
10
+ type AuthType = 0x00 | 0x01 | 0x02;
11
+ interface AuthScriptOptions {
12
+ authType?: AuthType;
11
13
  witnessScript?: Uint8Array | string;
12
14
  }
15
+ type PQAddressOptions = AuthScriptOptions;
13
16
  interface IPQAddressObject {
14
17
  address: string;
15
18
  mnemonic?: string;
@@ -17,7 +20,24 @@ interface IPQAddressObject {
17
20
  publicKey: string;
18
21
  privateKey: string;
19
22
  seedKey: string;
20
- authType: number;
23
+ authType: 0x01;
24
+ authDescriptor: string;
25
+ commitment: string;
26
+ witnessScript: string;
27
+ }
28
+ interface INoAuthAddressObject {
29
+ address: string;
30
+ authType: 0x00;
31
+ commitment: string;
32
+ witnessScript: string;
33
+ }
34
+ interface ILegacyAuthScriptAddressObject {
35
+ address: string;
36
+ path?: string;
37
+ publicKey: string;
38
+ privateKey: string;
39
+ WIF: string;
40
+ authType: 0x02;
21
41
  authDescriptor: string;
22
42
  commitment: string;
23
43
  witnessScript: string;
@@ -47,6 +67,29 @@ declare class HDKey {
47
67
  deriveChild(index: number): HDKey;
48
68
  }
49
69
 
70
+ declare const BIP32_PQ_EXTKEY_SIZE = 74;
71
+ declare class PQHDKey {
72
+ readonly depth: number;
73
+ readonly index: number;
74
+ readonly parentFingerprint: Uint8Array;
75
+ readonly chainCode: Uint8Array;
76
+ readonly pqSeed: Uint8Array;
77
+ private _publicKey?;
78
+ private _secretKey?;
79
+ constructor(depth: number, index: number, parentFingerprint: Uint8Array, chainCode: Uint8Array, pqSeed: Uint8Array);
80
+ static fromMasterSeed(seed: Uint8Array): PQHDKey;
81
+ private ensureKeypair;
82
+ get publicKey(): Uint8Array;
83
+ get secretKey(): Uint8Array;
84
+ get fingerprint(): Uint8Array;
85
+ deriveChild(index: number): PQHDKey;
86
+ encode(): Uint8Array;
87
+ encodeBase58Check(version: number): string;
88
+ static decode(raw: Uint8Array, parentFingerprint?: Uint8Array): PQHDKey;
89
+ static decodeBase58Check(extKey: string, expectedVersion: number): PQHDKey;
90
+ derive(path: string): PQHDKey;
91
+ }
92
+
50
93
  declare function getCoinType(network: Network): number;
51
94
  declare function getAddressPair(network: Network, mnemonic: string, account: number, position: number, passphrase?: string): {
52
95
  internal: IAddressObject;
@@ -67,8 +110,13 @@ declare function entropyToMnemonic(entropy: Uint8Array | string): string;
67
110
  declare function generateAddressObject(network?: Network, passphrase?: string): IAddressObject;
68
111
  declare function publicKeyToAddress(network: Network, publicKey: Uint8Array | string): string;
69
112
  declare function generateAddress(network?: Network): IAddressObject;
70
- declare function getPQHDKey(network: PQNetwork, mnemonic: string, passphrase?: string): HDKey;
71
- declare function getPQAddressByPath(network: PQNetwork, hdKey: HDKey, path: string, options?: PQAddressOptions): IPQAddressObject;
113
+ declare function getPQHDKey(_network: PQNetwork, mnemonic: string, passphrase?: string): PQHDKey;
114
+ declare function pqExtendedPrivateKey(network: PQNetwork, hdKey: PQHDKey): string;
115
+ declare function pqHDKeyFromExtended(network: PQNetwork, extKey: string): PQHDKey;
116
+ declare function getPQAddressByPath(network: PQNetwork, hdKey: PQHDKey, path: string, options?: PQAddressOptions): IPQAddressObject;
117
+ declare function getNoAuthAddress(network: PQNetwork, options?: AuthScriptOptions): INoAuthAddressObject;
118
+ declare function getLegacyAuthScriptAddress(network: PQNetwork, legacyNetwork: Network, mnemonic: string, account: number, index: number, passphrase?: string, options?: AuthScriptOptions): ILegacyAuthScriptAddressObject;
119
+ declare function getLegacyAuthScriptAddressByWIF(network: PQNetwork, wif: string, options?: AuthScriptOptions): ILegacyAuthScriptAddressObject;
72
120
  declare function getPQAddress(network: PQNetwork, mnemonic: string, account: number, index: number, passphrase?: string, options?: PQAddressOptions): IPQAddressObject;
73
121
  declare function pqPublicKeyToAddress(network: PQNetwork, publicKey: Uint8Array | string, options?: PQAddressOptions): string;
74
122
  declare function pqPublicKeyToCommitmentHex(publicKey: Uint8Array | string, options?: PQAddressOptions): string;
@@ -90,11 +138,16 @@ declare const NeuraiKey: {
90
138
  getPQAddress: typeof getPQAddress;
91
139
  getPQAddressByPath: typeof getPQAddressByPath;
92
140
  getPQHDKey: typeof getPQHDKey;
141
+ pqExtendedPrivateKey: typeof pqExtendedPrivateKey;
142
+ pqHDKeyFromExtended: typeof pqHDKeyFromExtended;
143
+ getNoAuthAddress: typeof getNoAuthAddress;
144
+ getLegacyAuthScriptAddress: typeof getLegacyAuthScriptAddress;
145
+ getLegacyAuthScriptAddressByWIF: typeof getLegacyAuthScriptAddressByWIF;
93
146
  pqPublicKeyToAddress: typeof pqPublicKeyToAddress;
94
147
  pqPublicKeyToAuthDescriptorHex: typeof pqPublicKeyToAuthDescriptorHex;
95
148
  pqPublicKeyToCommitmentHex: typeof pqPublicKeyToCommitmentHex;
96
149
  generatePQAddressObject: typeof generatePQAddressObject;
97
150
  };
98
151
 
99
- export { NeuraiKey as default, entropyToMnemonic, generateAddress, generateAddressObject, generateMnemonic, generatePQAddressObject, getAddressByPath, getAddressByWIF, getAddressPair, getCoinType, getHDKey, getPQAddress, getPQAddressByPath, getPQHDKey, getPubkeyByWIF, isMnemonicValid, pqPublicKeyToAddress, pqPublicKeyToAuthDescriptorHex, pqPublicKeyToCommitmentHex, publicKeyToAddress };
100
- export type { IAddressObject, IPQAddressObject, Network, PQAddressOptions, PQNetwork };
152
+ 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 };
153
+ export type { AuthScriptOptions, IAddressObject, ILegacyAuthScriptAddressObject, INoAuthAddressObject, IPQAddressObject, Network, PQAddressOptions, PQNetwork };
package/dist/index.js CHANGED
@@ -8,17 +8,25 @@ import { wordlist as wordlist$6 } from '@scure/bip39/wordlists/korean.js';
8
8
  import { wordlist as wordlist$7 } from '@scure/bip39/wordlists/portuguese.js';
9
9
  import { wordlist as wordlist$2 } from '@scure/bip39/wordlists/spanish.js';
10
10
  import { wordlist as wordlist$8 } from '@scure/bip39/wordlists/simplified-chinese.js';
11
- import { ml_dsa44 } from '@noble/post-quantum/ml-dsa.js';
12
11
  import { ripemd160 } from '@noble/hashes/legacy.js';
13
12
  import { hmac } from '@noble/hashes/hmac.js';
14
- import { sha256, sha512 } from '@noble/hashes/sha2.js';
15
- import { utf8ToBytes, bytesToHex as bytesToHex$1, hexToBytes as hexToBytes$1, concatBytes as concatBytes$1 } from '@noble/hashes/utils.js';
13
+ import { sha512, sha256 } from '@noble/hashes/sha2.js';
14
+ import { utf8ToBytes, concatBytes as concatBytes$1, bytesToHex as bytesToHex$1, hexToBytes as hexToBytes$1 } from '@noble/hashes/utils.js';
16
15
  import { secp256k1 } from '@noble/curves/secp256k1.js';
17
16
  import { bech32m } from 'bech32';
17
+ import { ml_dsa44 } from '@noble/post-quantum/ml-dsa.js';
18
18
 
19
19
  /*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
20
20
  function isBytes(a) {
21
- return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');
21
+ // Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases. The
22
+ // fallback still requires a real ArrayBuffer view, so plain JSON-deserialized
23
+ // `{ constructor: ... }` spoofing is rejected. `BYTES_PER_ELEMENT === 1` keeps the
24
+ // fallback on byte-oriented views.
25
+ return (a instanceof Uint8Array ||
26
+ (ArrayBuffer.isView(a) &&
27
+ a.constructor.name === 'Uint8Array' &&
28
+ 'BYTES_PER_ELEMENT' in a &&
29
+ a.BYTES_PER_ELEMENT === 1));
22
30
  }
23
31
  function isArrayOf(isString, arr) {
24
32
  if (!Array.isArray(arr))
@@ -34,24 +42,26 @@ function isArrayOf(isString, arr) {
34
42
  }
35
43
  function astr(label, input) {
36
44
  if (typeof input !== 'string')
37
- throw new Error(`${label}: string expected`);
45
+ throw new TypeError(`${label}: string expected`);
38
46
  return true;
39
47
  }
40
48
  function anumber(n) {
49
+ if (typeof n !== 'number')
50
+ throw new TypeError(`number expected, got ${typeof n}`);
41
51
  if (!Number.isSafeInteger(n))
42
- throw new Error(`invalid integer: ${n}`);
52
+ throw new RangeError(`invalid integer: ${n}`);
43
53
  }
44
54
  function aArr(input) {
45
55
  if (!Array.isArray(input))
46
- throw new Error('array expected');
56
+ throw new TypeError('array expected');
47
57
  }
48
58
  function astrArr(label, input) {
49
59
  if (!isArrayOf(true, input))
50
- throw new Error(`${label}: array of strings expected`);
60
+ throw new TypeError(`${label}: array of strings expected`);
51
61
  }
52
62
  function anumArr(label, input) {
53
63
  if (!isArrayOf(false, input))
54
- throw new Error(`${label}: array of numbers expected`);
64
+ throw new TypeError(`${label}: array of numbers expected`);
55
65
  }
56
66
  /**
57
67
  * @__NO_SIDE_EFFECTS__
@@ -104,6 +114,8 @@ function alphabet(letters) {
104
114
  */
105
115
  function join(separator = '') {
106
116
  astr('join', separator);
117
+ // join('') is only lossless when each chunk is already unambiguous, such as single-symbol alphabets.
118
+ // Multi-character tokens need a separator that cannot appear inside the chunks.
107
119
  return {
108
120
  encode: (from) => {
109
121
  astrArr('join.decode', from);
@@ -121,9 +133,9 @@ function join(separator = '') {
121
133
  function convertRadix(data, from, to) {
122
134
  // base 1 is impossible
123
135
  if (from < 2)
124
- throw new Error(`convertRadix: invalid from=${from}, base cannot be less than 2`);
136
+ throw new RangeError(`convertRadix: invalid from=${from}, base cannot be less than 2`);
125
137
  if (to < 2)
126
- throw new Error(`convertRadix: invalid to=${to}, base cannot be less than 2`);
138
+ throw new RangeError(`convertRadix: invalid to=${to}, base cannot be less than 2`);
127
139
  aArr(data);
128
140
  if (!data.length)
129
141
  return [];
@@ -165,6 +177,7 @@ function convertRadix(data, from, to) {
165
177
  if (done)
166
178
  break;
167
179
  }
180
+ // Preserve explicit leading zero digits so callers like base58 keep zero-prefix semantics.
168
181
  for (let i = 0; i < data.length - 1 && data[i] === 0; i++)
169
182
  res.push(0);
170
183
  return res.reverse();
@@ -175,10 +188,11 @@ function convertRadix(data, from, to) {
175
188
  function radix(num) {
176
189
  anumber(num);
177
190
  const _256 = 2 ** 8;
191
+ // Base-range and carry-overflow checks live in convertRadix so encode/decode reject unsupported bases symmetrically.
178
192
  return {
179
193
  encode: (bytes) => {
180
194
  if (!isBytes(bytes))
181
- throw new Error('radix.encode input should be Uint8Array');
195
+ throw new TypeError('radix.encode input should be Uint8Array');
182
196
  return convertRadix(Array.from(bytes), _256, num);
183
197
  },
184
198
  decode: (digits) => {
@@ -195,11 +209,12 @@ const genBase58 = /* @__NO_SIDE_EFFECTS__ */ (abc) => chain(radix(58), alphabet(
195
209
  * Quadratic (O(n^2)) - so, can't be used on large inputs.
196
210
  * @example
197
211
  * ```js
198
- * base58.decode('01abcdef');
199
- * // => '3UhJW'
212
+ * const text = base58.encode(Uint8Array.from([0, 1, 2]));
213
+ * base58.decode(text);
214
+ * // => Uint8Array.from([0, 1, 2])
200
215
  * ```
201
216
  */
202
- const base58 = genBase58('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
217
+ const base58 = /* @__PURE__ */ Object.freeze(genBase58('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'));
203
218
 
204
219
  const HARDENED_OFFSET = 0x80000000;
205
220
  const SECP256K1_ORDER = BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
@@ -290,7 +305,10 @@ const BITCOIN_SEED_KEY = utf8ToBytes("Bitcoin seed");
290
305
 
291
306
  const AUTHSCRIPT_TAG = "NeuraiAuthScript";
292
307
  const AUTHSCRIPT_VERSION = 0x01;
308
+ const NOAUTH_TYPE = 0x00;
293
309
  const PQ_AUTH_TYPE = 0x01;
310
+ const LEGACY_AUTH_TYPE = 0x02;
311
+ const PQ_PUBLIC_KEY_HEADER$1 = Uint8Array.from([0x05]);
294
312
  const DEFAULT_WITNESS_SCRIPT = Uint8Array.from([0x51]);
295
313
  function encodeWIF(privateKey, version, compressed = true) {
296
314
  const payload = compressed
@@ -351,27 +369,51 @@ function bech32mEncode(hrp, witnessVersion, hash) {
351
369
  function normalizeWitnessScript(input) {
352
370
  return input ? ensureBytes(input) : Uint8Array.from(DEFAULT_WITNESS_SCRIPT);
353
371
  }
372
+ function buildAuthDescriptor(authType, publicKey) {
373
+ if (authType === NOAUTH_TYPE) {
374
+ return Uint8Array.from([NOAUTH_TYPE]);
375
+ }
376
+ if (!publicKey) {
377
+ throw new Error(`Auth type 0x${authType.toString(16).padStart(2, "0")} requires a public key`);
378
+ }
379
+ if (authType === PQ_AUTH_TYPE) {
380
+ return concatBytes(Uint8Array.from([PQ_AUTH_TYPE]), hash160(concatBytes(PQ_PUBLIC_KEY_HEADER$1, publicKey)));
381
+ }
382
+ if (authType === LEGACY_AUTH_TYPE) {
383
+ return concatBytes(Uint8Array.from([LEGACY_AUTH_TYPE]), hash160(publicKey));
384
+ }
385
+ throw new Error(`Unsupported authType: 0x${String(authType).padStart(2, "0")}`);
386
+ }
354
387
  function pqPublicKeyToAuthDescriptor(publicKey) {
355
- return concatBytes(Uint8Array.from([PQ_AUTH_TYPE]), hash160(publicKey));
388
+ return buildAuthDescriptor(PQ_AUTH_TYPE, publicKey);
356
389
  }
357
390
  function pqPublicKeyToCommitment(publicKey, options = {}) {
358
391
  return pqPublicKeyToCommitmentParts(publicKey, options).commitment;
359
392
  }
360
- function pqPublicKeyToCommitmentParts(publicKey, options = {}) {
393
+ function authScriptCommitmentParts(authType, publicKey, options = {}) {
361
394
  const witnessScript = normalizeWitnessScript(options.witnessScript);
362
- const authDescriptor = pqPublicKeyToAuthDescriptor(publicKey);
395
+ const authDescriptor = buildAuthDescriptor(authType, publicKey);
363
396
  const witnessScriptHash = sha256Hash(witnessScript);
364
397
  const commitment = taggedHash(AUTHSCRIPT_TAG, concatBytes(Uint8Array.from([AUTHSCRIPT_VERSION]), authDescriptor, witnessScriptHash));
365
398
  return {
366
399
  authDescriptor,
367
- authType: PQ_AUTH_TYPE,
400
+ authType,
368
401
  commitment,
369
402
  witnessScript,
370
403
  };
371
404
  }
405
+ function pqPublicKeyToCommitmentParts(publicKey, options = {}) {
406
+ return authScriptCommitmentParts(PQ_AUTH_TYPE, publicKey, options);
407
+ }
372
408
  function pqPublicKeyToAddressBytes(publicKey, network, options = {}) {
373
409
  return bech32mEncode(network.hrp, network.witnessVersion, pqPublicKeyToCommitment(publicKey, options));
374
410
  }
411
+ function noAuthToAddressBytes(network, options = {}) {
412
+ return bech32mEncode(network.hrp, network.witnessVersion, authScriptCommitmentParts(NOAUTH_TYPE, null, options).commitment);
413
+ }
414
+ function legacyAuthScriptToAddressBytes(publicKey, network, options = {}) {
415
+ return bech32mEncode(network.hrp, network.witnessVersion, authScriptCommitmentParts(LEGACY_AUTH_TYPE, publicKey, options).commitment);
416
+ }
375
417
  function normalizePublicKey(input) {
376
418
  return ensureBytes(input);
377
419
  }
@@ -481,6 +523,122 @@ class HDKey {
481
523
  }
482
524
  }
483
525
 
526
+ const PQ_SEED_KEY = utf8ToBytes("Neurai PQ seed");
527
+ const PQ_PUBLIC_KEY_HEADER = 0x05;
528
+ // 74-byte layout, padded to match BIP32 xprv so base58check yields "xpqp..."/"tpqp...":
529
+ // depth(1) + fingerprint(4) + child(4) + chaincode(32) + padding(1=0x00) + pq_seed(32)
530
+ const BIP32_PQ_EXTKEY_SIZE = 74;
531
+ class PQHDKey {
532
+ constructor(depth, index, parentFingerprint, chainCode, pqSeed) {
533
+ this.depth = depth;
534
+ this.index = index;
535
+ this.parentFingerprint = parentFingerprint;
536
+ this.chainCode = chainCode;
537
+ this.pqSeed = pqSeed;
538
+ }
539
+ static fromMasterSeed(seed) {
540
+ const I = hmacSha512(PQ_SEED_KEY, seed);
541
+ return new PQHDKey(0, 0, new Uint8Array(4), I.slice(32, 64), I.slice(0, 32));
542
+ }
543
+ ensureKeypair() {
544
+ if (!this._publicKey || !this._secretKey) {
545
+ const { publicKey, secretKey } = ml_dsa44.keygen(this.pqSeed);
546
+ this._publicKey = publicKey;
547
+ this._secretKey = secretKey;
548
+ }
549
+ }
550
+ get publicKey() {
551
+ this.ensureKeypair();
552
+ return this._publicKey;
553
+ }
554
+ get secretKey() {
555
+ this.ensureKeypair();
556
+ return this._secretKey;
557
+ }
558
+ get fingerprint() {
559
+ return hash160(concatBytes(Uint8Array.from([PQ_PUBLIC_KEY_HEADER]), this.publicKey)).slice(0, 4);
560
+ }
561
+ deriveChild(index) {
562
+ if ((index & HARDENED_OFFSET) === 0) {
563
+ throw new Error("PQ-HD (NIP-022) requires hardened derivation at every level");
564
+ }
565
+ const data = concatBytes(Uint8Array.from([0x00]), this.pqSeed, uint32ToBytesBE(index >>> 0));
566
+ const I = hmacSha512(this.chainCode, data);
567
+ return new PQHDKey(this.depth + 1, index >>> 0, this.fingerprint, I.slice(32, 64), I.slice(0, 32));
568
+ }
569
+ encode() {
570
+ const out = new Uint8Array(BIP32_PQ_EXTKEY_SIZE);
571
+ out[0] = this.depth & 0xff;
572
+ out.set(this.parentFingerprint, 1);
573
+ out[5] = (this.index >>> 24) & 0xff;
574
+ out[6] = (this.index >>> 16) & 0xff;
575
+ out[7] = (this.index >>> 8) & 0xff;
576
+ out[8] = this.index & 0xff;
577
+ out.set(this.chainCode, 9);
578
+ out[41] = 0x00; // padding byte (aligns layout with BIP32 xprv)
579
+ out.set(this.pqSeed, 42);
580
+ return out;
581
+ }
582
+ encodeBase58Check(version) {
583
+ const versionBytes = Uint8Array.from([
584
+ (version >>> 24) & 0xff,
585
+ (version >>> 16) & 0xff,
586
+ (version >>> 8) & 0xff,
587
+ version & 0xff,
588
+ ]);
589
+ return base58CheckEncode(concatBytes(versionBytes, this.encode()));
590
+ }
591
+ static decode(raw, parentFingerprint) {
592
+ if (raw.length !== BIP32_PQ_EXTKEY_SIZE) {
593
+ throw new Error(`PQ extended key payload must be ${BIP32_PQ_EXTKEY_SIZE} bytes`);
594
+ }
595
+ if (raw[41] !== 0x00) {
596
+ throw new Error("PQ extended key padding byte (offset 41) must be 0x00");
597
+ }
598
+ const depth = raw[0];
599
+ const fingerprint = parentFingerprint ?? raw.slice(1, 5);
600
+ const index = ((raw[5] << 24) | (raw[6] << 16) | (raw[7] << 8) | raw[8]) >>> 0;
601
+ const chainCode = raw.slice(9, 41);
602
+ const pqSeed = raw.slice(42, 74);
603
+ return new PQHDKey(depth, index, Uint8Array.from(fingerprint.slice(0, 4)), chainCode, pqSeed);
604
+ }
605
+ static decodeBase58Check(extKey, expectedVersion) {
606
+ const payload = base58CheckDecode(extKey);
607
+ if (payload.length !== 4 + BIP32_PQ_EXTKEY_SIZE) {
608
+ throw new Error("Invalid PQ extended key length");
609
+ }
610
+ const version = ((payload[0] << 24) | (payload[1] << 16) | (payload[2] << 8) | payload[3]) >>> 0;
611
+ if (version !== (expectedVersion >>> 0)) {
612
+ throw new Error(`PQ extended key version mismatch (expected 0x${expectedVersion.toString(16)}, got 0x${version.toString(16)})`);
613
+ }
614
+ return PQHDKey.decode(payload.slice(4));
615
+ }
616
+ derive(path) {
617
+ const entries = path.split("/");
618
+ const root = entries[0];
619
+ if (root !== "m" && root !== "M" && root !== "m_pq" && root !== "M_pq") {
620
+ throw new Error('PQ path must start with "m_pq" (or "m")');
621
+ }
622
+ if (entries.length === 1) {
623
+ return this;
624
+ }
625
+ let current = this;
626
+ for (let i = 1; i < entries.length; i += 1) {
627
+ const entry = entries[i];
628
+ const hardened = entry.endsWith("'");
629
+ if (!hardened) {
630
+ throw new Error(`PQ-HD path requires hardened indices (got "${entry}")`);
631
+ }
632
+ const raw = Number.parseInt(entry.slice(0, -1), 10);
633
+ if (!Number.isFinite(raw) || raw < 0 || raw >= HARDENED_OFFSET) {
634
+ throw new Error(`Invalid PQ-HD index "${entry}"`);
635
+ }
636
+ current = current.deriveChild(raw + HARDENED_OFFSET);
637
+ }
638
+ return current;
639
+ }
640
+ }
641
+
484
642
  const currentNetworks = {
485
643
  xna: {
486
644
  versions: {
@@ -526,7 +684,7 @@ const pqNetworks = {
526
684
  purpose: 100,
527
685
  coinType: 1900,
528
686
  changeIndex: 0,
529
- bip32: { private: 76066276, public: 76067358 },
687
+ pqExtPrivVersion: 0x0488ac24, // "xpqp..." prefix, matches Neurai node chainparams.cpp
530
688
  },
531
689
  "xna-pq-test": {
532
690
  hrp: "tnq",
@@ -534,7 +692,7 @@ const pqNetworks = {
534
692
  purpose: 100,
535
693
  coinType: 1,
536
694
  changeIndex: 0,
537
- bip32: { private: 70615956, public: 70617039 },
695
+ pqExtPrivVersion: 0x043581d5, // "tpqp..." prefix, matches Neurai node chainparams.cpp
538
696
  },
539
697
  };
540
698
  function getNetwork(name) {
@@ -625,36 +783,89 @@ function publicKeyToAddress(network, publicKey) {
625
783
  function generateAddress(network = "xna") {
626
784
  return generateAddressObject(network);
627
785
  }
628
- function getPQHDKey(network, mnemonic, passphrase = "") {
629
- const chain = getPQNetwork(network);
786
+ function getPQHDKey(_network, mnemonic, passphrase = "") {
630
787
  const seed = mnemonicToSeedBytes(mnemonicToSeedSync, mnemonic, passphrase);
631
- return HDKey.fromMasterSeed(seed, chain.bip32);
788
+ return PQHDKey.fromMasterSeed(seed);
789
+ }
790
+ function pqExtendedPrivateKey(network, hdKey) {
791
+ return hdKey.encodeBase58Check(getPQNetwork(network).pqExtPrivVersion);
792
+ }
793
+ function pqHDKeyFromExtended(network, extKey) {
794
+ return PQHDKey.decodeBase58Check(extKey, getPQNetwork(network).pqExtPrivVersion);
632
795
  }
633
796
  function getPQAddressByPath(network, hdKey, path, options = {}) {
634
797
  const chain = getPQNetwork(network);
635
798
  const derived = hdKey.derive(path);
636
- if (!derived.privateKey) {
637
- throw new Error("Could not derive private key for path");
638
- }
639
- const seed32 = Uint8Array.from(derived.privateKey);
640
- const { publicKey, secretKey } = ml_dsa44.keygen(seed32);
799
+ const publicKey = derived.publicKey;
800
+ const secretKey = derived.secretKey;
641
801
  const authScript = pqPublicKeyToCommitmentParts(publicKey, options);
642
802
  return {
643
803
  address: pqPublicKeyToAddressBytes(publicKey, chain, options),
644
- authType: authScript.authType,
804
+ authType: 0x01,
645
805
  authDescriptor: bytesToHex(authScript.authDescriptor),
646
806
  commitment: bytesToHex(authScript.commitment),
647
807
  path,
648
808
  publicKey: bytesToHex(publicKey),
649
809
  privateKey: bytesToHex(secretKey),
650
- seedKey: bytesToHex(seed32),
810
+ seedKey: bytesToHex(derived.pqSeed),
651
811
  witnessScript: bytesToHex(authScript.witnessScript),
652
812
  };
653
813
  }
814
+ function getNoAuthAddress(network, options = {}) {
815
+ const chain = getPQNetwork(network);
816
+ const parts = authScriptCommitmentParts(0x00, null, options);
817
+ return {
818
+ address: noAuthToAddressBytes(chain, options),
819
+ authType: 0x00,
820
+ commitment: bytesToHex(parts.commitment),
821
+ witnessScript: bytesToHex(parts.witnessScript),
822
+ };
823
+ }
824
+ function getLegacyAuthScriptAddress(network, legacyNetwork, mnemonic, account, index, passphrase = "", options = {}) {
825
+ const pqChain = getPQNetwork(network);
826
+ const legacyChain = getNetwork(legacyNetwork);
827
+ const coinType = legacyChain.bip44;
828
+ const hdKey = getHDKey(legacyNetwork, mnemonic, passphrase);
829
+ const path = `m/44'/${coinType}'/${account}'/0/${index}`;
830
+ const derived = hdKey.derive(path);
831
+ if (!derived.privateKey) {
832
+ throw new Error("Could not derive private key for path");
833
+ }
834
+ const legacyObject = privateKeyToAddressObject(derived.privateKey, legacyChain, path);
835
+ const publicKeyBytes = ensureBytes(legacyObject.publicKey);
836
+ const parts = authScriptCommitmentParts(0x02, publicKeyBytes, options);
837
+ return {
838
+ address: legacyAuthScriptToAddressBytes(publicKeyBytes, pqChain, options),
839
+ path,
840
+ publicKey: legacyObject.publicKey,
841
+ privateKey: legacyObject.privateKey,
842
+ WIF: legacyObject.WIF,
843
+ authType: 0x02,
844
+ authDescriptor: bytesToHex(parts.authDescriptor),
845
+ commitment: bytesToHex(parts.commitment),
846
+ witnessScript: bytesToHex(parts.witnessScript),
847
+ };
848
+ }
849
+ function getLegacyAuthScriptAddressByWIF(network, wif, options = {}) {
850
+ const pqChain = getPQNetwork(network);
851
+ const publicKeyHex = publicKeyHexFromWIF(wif);
852
+ const publicKeyBytes = ensureBytes(publicKeyHex);
853
+ const parts = authScriptCommitmentParts(0x02, publicKeyBytes, options);
854
+ return {
855
+ address: legacyAuthScriptToAddressBytes(publicKeyBytes, pqChain, options),
856
+ publicKey: publicKeyHex,
857
+ privateKey: "",
858
+ WIF: wif,
859
+ authType: 0x02,
860
+ authDescriptor: bytesToHex(parts.authDescriptor),
861
+ commitment: bytesToHex(parts.commitment),
862
+ witnessScript: bytesToHex(parts.witnessScript),
863
+ };
864
+ }
654
865
  function getPQAddress(network, mnemonic, account, index, passphrase = "", options = {}) {
655
866
  const chain = getPQNetwork(network);
656
867
  const hdKey = getPQHDKey(network, mnemonic, passphrase);
657
- const path = `m/${chain.purpose}'/${chain.coinType}'/${account}'/${chain.changeIndex}/${index}`;
868
+ const path = `m_pq/${chain.purpose}'/${chain.coinType}'/${account}'/${chain.changeIndex}'/${index}'`;
658
869
  return getPQAddressByPath(network, hdKey, path, options);
659
870
  }
660
871
  function pqPublicKeyToAddress(network, publicKey, options = {}) {
@@ -703,11 +914,16 @@ const NeuraiKey = {
703
914
  getPQAddress,
704
915
  getPQAddressByPath,
705
916
  getPQHDKey,
917
+ pqExtendedPrivateKey,
918
+ pqHDKeyFromExtended,
919
+ getNoAuthAddress,
920
+ getLegacyAuthScriptAddress,
921
+ getLegacyAuthScriptAddressByWIF,
706
922
  pqPublicKeyToAddress,
707
923
  pqPublicKeyToAuthDescriptorHex,
708
924
  pqPublicKeyToCommitmentHex,
709
925
  generatePQAddressObject,
710
926
  };
711
927
 
712
- export { NeuraiKey as default, entropyToMnemonic, generateAddress, generateAddressObject, generateMnemonic, generatePQAddressObject, getAddressByPath, getAddressByWIF, getAddressPair, getCoinType, getHDKey, getPQAddress, getPQAddressByPath, getPQHDKey, getPubkeyByWIF, isMnemonicValid, pqPublicKeyToAddress, pqPublicKeyToAuthDescriptorHex, pqPublicKeyToCommitmentHex, publicKeyToAddress };
928
+ 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 };
713
929
  //# sourceMappingURL=index.js.map