@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/README.md +136 -16
- package/dist/NeuraiKey.global.js +5777 -4118
- package/dist/NeuraiKey.global.js.map +1 -1
- package/dist/browser.js +5778 -4119
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +5785 -4118
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +59 -6
- package/dist/index.js +249 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,9 +7,12 @@ interface IAddressObject {
|
|
|
7
7
|
privateKey: string;
|
|
8
8
|
WIF: string;
|
|
9
9
|
}
|
|
10
|
-
|
|
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:
|
|
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(
|
|
71
|
-
declare function
|
|
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 {
|
|
15
|
-
import { utf8ToBytes,
|
|
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
|
-
|
|
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
|
|
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
|
|
52
|
+
throw new RangeError(`invalid integer: ${n}`);
|
|
43
53
|
}
|
|
44
54
|
function aArr(input) {
|
|
45
55
|
if (!Array.isArray(input))
|
|
46
|
-
throw new
|
|
56
|
+
throw new TypeError('array expected');
|
|
47
57
|
}
|
|
48
58
|
function astrArr(label, input) {
|
|
49
59
|
if (!isArrayOf(true, input))
|
|
50
|
-
throw new
|
|
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
|
|
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
|
|
136
|
+
throw new RangeError(`convertRadix: invalid from=${from}, base cannot be less than 2`);
|
|
125
137
|
if (to < 2)
|
|
126
|
-
throw new
|
|
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
|
|
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.
|
|
199
|
-
*
|
|
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
|
|
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
|
|
393
|
+
function authScriptCommitmentParts(authType, publicKey, options = {}) {
|
|
361
394
|
const witnessScript = normalizeWitnessScript(options.witnessScript);
|
|
362
|
-
const authDescriptor =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
629
|
-
const chain = getPQNetwork(network);
|
|
786
|
+
function getPQHDKey(_network, mnemonic, passphrase = "") {
|
|
630
787
|
const seed = mnemonicToSeedBytes(mnemonicToSeedSync, mnemonic, passphrase);
|
|
631
|
-
return
|
|
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
|
-
|
|
637
|
-
|
|
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:
|
|
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(
|
|
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 = `
|
|
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
|