@neuraiproject/neurai-key 3.0.2 → 3.1.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 CHANGED
@@ -5,7 +5,7 @@ Generate Neurai addresses from a mnemonic phrase following the standards BIP32,
5
5
  That is, use your 12 words to get addresses for Neurai mainnet and testnet.
6
6
 
7
7
  **NPM**: https://www.npmjs.com/package/@neuraiproject/neurai-key
8
- **CDN**: https://cdn.jsdelivr.net/npm/@neuraiproject/neurai-key@3.0.0/dist/NeuraiKey.global.js
8
+ **CDN**: https://cdn.jsdelivr.net/npm/@neuraiproject/neurai-key@3.1.0/dist/NeuraiKey.global.js
9
9
 
10
10
  ## Features
11
11
 
@@ -16,7 +16,16 @@ That is, use your 12 words to get addresses for Neurai mainnet and testnet.
16
16
  - ✅ Mainnet and Testnet support for Neurai (XNA)
17
17
  - ✅ Support for both XNA (BIP44: 1900) and XNA Legacy (BIP44: 0) networks
18
18
  - ✅ Convert raw public keys into Neurai mainnet or testnet addresses
19
- - ✅ PostQuantum AuthScript addresses using ML-DSA-44 (FIPS 204) with Bech32m encoding
19
+ - ✅ AuthScript witness v1 addresses with Bech32m encoding
20
+ - ✅ `authType = 0x00` NoAuth addresses from `witnessScript` only
21
+ - ✅ `authType = 0x01` PostQuantum ML-DSA-44 AuthScript addresses
22
+ - ✅ `authType = 0x02` Legacy secp256k1 AuthScript addresses
23
+
24
+ ## Compatibility Note
25
+
26
+ Starting in `3.1.0`, PQ AuthScript descriptors are computed as `0x01 || HASH160(0x05 || rawPublicKey)` to match `neurai-sign-transaction` and the node implementation.
27
+
28
+ This changes PQ AuthScript addresses and commitments compared to older releases of this library. If you previously generated PQ addresses with an older version of `neurai-key`, treat them as legacy outputs and verify fund exposure before migrating.
20
29
 
21
30
  ## Network Types
22
31
 
@@ -24,7 +33,7 @@ This library supports three Neurai network configurations:
24
33
 
25
34
  - **`xna` / `xna-test`**: Current Neurai standard (BIP44 coin type: 1900)
26
35
  - **`xna-legacy` / `xna-legacy-test`**: Legacy Neurai addresses (BIP44 coin type: 0)
27
- - **`xna-pq` / `xna-pq-test`**: PostQuantum ML-DSA-44 AuthScript addresses (Bech32m, witness v1)
36
+ - **`xna-pq` / `xna-pq-test`**: AuthScript witness v1 addresses (Bech32m, `nq1` / `tnq1`)
28
37
 
29
38
  The main difference is the derivation path and address encoding:
30
39
  - **XNA**: mainnet `m/44'/1900'/0'/0/0`, testnet `m/44'/1'/0'/0/0` — Base58Check (recommended for new wallets)
@@ -185,6 +194,14 @@ console.log(testAddress); // tPXGaMRNwZuV1UKSrD9gABPscrJWUmedQ9
185
194
 
186
195
  Generate quantum-resistant AuthScript addresses using the ML-DSA-44 signature scheme (FIPS 204). The library now follows the migrated `witness v1 = AuthScript` layout, so the Bech32m program is a 32-byte commitment instead of the old 20-byte PQ keyhash.
187
196
 
197
+ Supported AuthScript variants:
198
+
199
+ | `authType` | Name | Description |
200
+ |------------|------|-------------|
201
+ | `0x00` | NoAuth | No signature. Spend path depends only on `witnessScript` |
202
+ | `0x01` | PQ | ML-DSA-44 post-quantum signature |
203
+ | `0x02` | Legacy | secp256k1 signature inside the AuthScript framework |
204
+
188
205
  ### Generate a PQ address
189
206
 
190
207
  ```javascript
@@ -207,7 +224,7 @@ Outputs
207
224
  {
208
225
  address: 'nq1...', // Bech32m AuthScript address
209
226
  authType: 1, // 0x01 = PQ single-key auth
210
- authDescriptor: '01...', // 0x01 || HASH160(pq_pubkey)
227
+ authDescriptor: '01...', // 0x01 || HASH160(0x05 || pq_pubkey)
211
228
  commitment: '...', // tagged_hash("NeuraiAuthScript", ...)
212
229
  path: "m/100'/1900'/0'/0/0", // PQ derivation path
213
230
  publicKey: '...', // ML-DSA-44 public key (2624 hex chars = 1312 bytes)
@@ -244,7 +261,84 @@ console.log(pqAddress.witnessScript); // 5151
244
261
  console.log(pqAddress.commitment); // new 32-byte commitment
245
262
  ```
246
263
 
247
- `authType` no es configurable en la API pública. Esta librería genera únicamente direcciones PQ simples con `authType = 0x01`.
264
+ `getPQAddress()` always generates `authType = 0x01` PQ addresses. Use `getNoAuthAddress()` for `0x00` and `getLegacyAuthScriptAddress()` / `getLegacyAuthScriptAddressByWIF()` for `0x02`.
265
+
266
+ ### Generate a NoAuth address
267
+
268
+ ```javascript
269
+ import NeuraiKey from "@neuraiproject/neurai-key";
270
+
271
+ const noAuth = NeuraiKey.getNoAuthAddress("xna-pq-test");
272
+
273
+ console.log(noAuth);
274
+ ```
275
+
276
+ Outputs
277
+
278
+ ```javascript
279
+ {
280
+ address: "tnq1...",
281
+ authType: 0,
282
+ commitment: "...",
283
+ witnessScript: "51"
284
+ }
285
+ ```
286
+
287
+ You can provide a custom `witnessScript`:
288
+
289
+ ```javascript
290
+ const noAuth = NeuraiKey.getNoAuthAddress("xna-pq-test", {
291
+ witnessScript: "527551"
292
+ });
293
+ ```
294
+
295
+ ### Generate a Legacy AuthScript address from mnemonic
296
+
297
+ This derives a normal secp256k1 key using the selected legacy/current HD network, then wraps it as an AuthScript address using the PQ Bech32m network.
298
+
299
+ ```javascript
300
+ import NeuraiKey from "@neuraiproject/neurai-key";
301
+
302
+ const mnemonic = "result pact model attract result puzzle final boss private educate luggage era";
303
+
304
+ const legacyAuth = NeuraiKey.getLegacyAuthScriptAddress(
305
+ "xna-pq-test",
306
+ "xna-test",
307
+ mnemonic,
308
+ 0,
309
+ 0
310
+ );
311
+
312
+ console.log(legacyAuth);
313
+ ```
314
+
315
+ Outputs
316
+
317
+ ```javascript
318
+ {
319
+ address: "tnq1...",
320
+ path: "m/44'/1'/0'/0/0",
321
+ publicKey: "...", // compressed secp256k1 pubkey
322
+ privateKey: "...",
323
+ WIF: "...",
324
+ authType: 2,
325
+ authDescriptor: "02...",
326
+ commitment: "...",
327
+ witnessScript: "51"
328
+ }
329
+ ```
330
+
331
+ ### Generate a Legacy AuthScript address from WIF
332
+
333
+ ```javascript
334
+ import NeuraiKey from "@neuraiproject/neurai-key";
335
+
336
+ const wif = "cVP9mzcDqMzWDhekiKMWKqEy739Cp6rKDT4tbG4wXXVfopMfTiBW";
337
+ const legacyAuth = NeuraiKey.getLegacyAuthScriptAddressByWIF("xna-pq-test", wif);
338
+
339
+ console.log(legacyAuth.address);
340
+ console.log(legacyAuth.publicKey);
341
+ ```
248
342
 
249
343
  ### Advanced: derive by path with HD key reuse
250
344
 
@@ -265,7 +359,7 @@ const addr1 = NeuraiKey.getPQAddressByPath("xna-pq", hdKey, "m/100'/1900'/0'/0/1
265
359
  | Public key size | 1312 bytes |
266
360
  | Derivation path (mainnet) | `m/100'/1900'/0'/0/index` |
267
361
  | Derivation path (testnet default/external) | `m/100'/1'/account'/0/index` |
268
- | Auth descriptor | `0x01 \|\| HASH160(pq_pubkey)` |
362
+ | Auth descriptor | `0x01 \|\| HASH160(0x05 \|\| pq_pubkey)` |
269
363
  | Commitment | `tagged_hash("NeuraiAuthScript", 0x01 \|\| auth_descriptor \|\| SHA256(witnessScript))` |
270
364
  | Default witnessScript | `OP_TRUE` (`51` in hex) |
271
365
 
@@ -318,7 +412,7 @@ const NeuraiKey = require("@neuraiproject/neurai-key");
318
412
  </html>
319
413
  ```
320
414
 
321
- ## Package layout in `3.0.0`
415
+ ## Package layout in `3.1.0`
322
416
 
323
417
  - `dist/index.js`: ESM main entry
324
418
  - `dist/index.cjs`: CommonJS entry
@@ -338,7 +432,7 @@ const NeuraiKey = require("@neuraiproject/neurai-key");
338
432
 
339
433
  `npm test`
340
434
 
341
- The test script already builds the package before running Jest.
435
+ The test script already builds the package before running Vitest.
342
436
 
343
437
  ## BIP32
344
438
 
@@ -23716,7 +23716,10 @@ zurdo`.split('\n');
23716
23716
 
23717
23717
  const AUTHSCRIPT_TAG = "NeuraiAuthScript";
23718
23718
  const AUTHSCRIPT_VERSION = 0x01;
23719
+ const NOAUTH_TYPE = 0x00;
23719
23720
  const PQ_AUTH_TYPE = 0x01;
23721
+ const LEGACY_AUTH_TYPE = 0x02;
23722
+ const PQ_PUBLIC_KEY_HEADER = Uint8Array.from([0x05]);
23720
23723
  const DEFAULT_WITNESS_SCRIPT = Uint8Array.from([0x51]);
23721
23724
  function encodeWIF(privateKey, version, compressed = true) {
23722
23725
  const payload = compressed
@@ -23777,27 +23780,51 @@ zurdo`.split('\n');
23777
23780
  function normalizeWitnessScript(input) {
23778
23781
  return input ? ensureBytes(input) : Uint8Array.from(DEFAULT_WITNESS_SCRIPT);
23779
23782
  }
23783
+ function buildAuthDescriptor(authType, publicKey) {
23784
+ if (authType === NOAUTH_TYPE) {
23785
+ return Uint8Array.from([NOAUTH_TYPE]);
23786
+ }
23787
+ if (!publicKey) {
23788
+ throw new Error(`Auth type 0x${authType.toString(16).padStart(2, "0")} requires a public key`);
23789
+ }
23790
+ if (authType === PQ_AUTH_TYPE) {
23791
+ return concatBytes(Uint8Array.from([PQ_AUTH_TYPE]), hash160(concatBytes(PQ_PUBLIC_KEY_HEADER, publicKey)));
23792
+ }
23793
+ if (authType === LEGACY_AUTH_TYPE) {
23794
+ return concatBytes(Uint8Array.from([LEGACY_AUTH_TYPE]), hash160(publicKey));
23795
+ }
23796
+ throw new Error(`Unsupported authType: 0x${String(authType).padStart(2, "0")}`);
23797
+ }
23780
23798
  function pqPublicKeyToAuthDescriptor(publicKey) {
23781
- return concatBytes(Uint8Array.from([PQ_AUTH_TYPE]), hash160(publicKey));
23799
+ return buildAuthDescriptor(PQ_AUTH_TYPE, publicKey);
23782
23800
  }
23783
23801
  function pqPublicKeyToCommitment(publicKey, options = {}) {
23784
23802
  return pqPublicKeyToCommitmentParts(publicKey, options).commitment;
23785
23803
  }
23786
- function pqPublicKeyToCommitmentParts(publicKey, options = {}) {
23804
+ function authScriptCommitmentParts(authType, publicKey, options = {}) {
23787
23805
  const witnessScript = normalizeWitnessScript(options.witnessScript);
23788
- const authDescriptor = pqPublicKeyToAuthDescriptor(publicKey);
23806
+ const authDescriptor = buildAuthDescriptor(authType, publicKey);
23789
23807
  const witnessScriptHash = sha256Hash(witnessScript);
23790
23808
  const commitment = taggedHash(AUTHSCRIPT_TAG, concatBytes(Uint8Array.from([AUTHSCRIPT_VERSION]), authDescriptor, witnessScriptHash));
23791
23809
  return {
23792
23810
  authDescriptor,
23793
- authType: PQ_AUTH_TYPE,
23811
+ authType,
23794
23812
  commitment,
23795
23813
  witnessScript,
23796
23814
  };
23797
23815
  }
23816
+ function pqPublicKeyToCommitmentParts(publicKey, options = {}) {
23817
+ return authScriptCommitmentParts(PQ_AUTH_TYPE, publicKey, options);
23818
+ }
23798
23819
  function pqPublicKeyToAddressBytes(publicKey, network, options = {}) {
23799
23820
  return bech32mEncode(network.hrp, network.witnessVersion, pqPublicKeyToCommitment(publicKey, options));
23800
23821
  }
23822
+ function noAuthToAddressBytes(network, options = {}) {
23823
+ return bech32mEncode(network.hrp, network.witnessVersion, authScriptCommitmentParts(NOAUTH_TYPE, null, options).commitment);
23824
+ }
23825
+ function legacyAuthScriptToAddressBytes(publicKey, network, options = {}) {
23826
+ return bech32mEncode(network.hrp, network.witnessVersion, authScriptCommitmentParts(LEGACY_AUTH_TYPE, publicKey, options).commitment);
23827
+ }
23801
23828
  function normalizePublicKey(input) {
23802
23829
  return ensureBytes(input);
23803
23830
  }
@@ -24067,7 +24094,7 @@ zurdo`.split('\n');
24067
24094
  const authScript = pqPublicKeyToCommitmentParts(publicKey, options);
24068
24095
  return {
24069
24096
  address: pqPublicKeyToAddressBytes(publicKey, chain, options),
24070
- authType: authScript.authType,
24097
+ authType: 0x01,
24071
24098
  authDescriptor: bytesToHex(authScript.authDescriptor),
24072
24099
  commitment: bytesToHex(authScript.commitment),
24073
24100
  path,
@@ -24077,6 +24104,57 @@ zurdo`.split('\n');
24077
24104
  witnessScript: bytesToHex(authScript.witnessScript),
24078
24105
  };
24079
24106
  }
24107
+ function getNoAuthAddress(network, options = {}) {
24108
+ const chain = getPQNetwork(network);
24109
+ const parts = authScriptCommitmentParts(0x00, null, options);
24110
+ return {
24111
+ address: noAuthToAddressBytes(chain, options),
24112
+ authType: 0x00,
24113
+ commitment: bytesToHex(parts.commitment),
24114
+ witnessScript: bytesToHex(parts.witnessScript),
24115
+ };
24116
+ }
24117
+ function getLegacyAuthScriptAddress(network, legacyNetwork, mnemonic, account, index, passphrase = "", options = {}) {
24118
+ const pqChain = getPQNetwork(network);
24119
+ const legacyChain = getNetwork(legacyNetwork);
24120
+ const coinType = legacyChain.bip44;
24121
+ const hdKey = getHDKey(legacyNetwork, mnemonic, passphrase);
24122
+ const path = `m/44'/${coinType}'/${account}'/0/${index}`;
24123
+ const derived = hdKey.derive(path);
24124
+ if (!derived.privateKey) {
24125
+ throw new Error("Could not derive private key for path");
24126
+ }
24127
+ const legacyObject = privateKeyToAddressObject(derived.privateKey, legacyChain, path);
24128
+ const publicKeyBytes = ensureBytes(legacyObject.publicKey);
24129
+ const parts = authScriptCommitmentParts(0x02, publicKeyBytes, options);
24130
+ return {
24131
+ address: legacyAuthScriptToAddressBytes(publicKeyBytes, pqChain, options),
24132
+ path,
24133
+ publicKey: legacyObject.publicKey,
24134
+ privateKey: legacyObject.privateKey,
24135
+ WIF: legacyObject.WIF,
24136
+ authType: 0x02,
24137
+ authDescriptor: bytesToHex(parts.authDescriptor),
24138
+ commitment: bytesToHex(parts.commitment),
24139
+ witnessScript: bytesToHex(parts.witnessScript),
24140
+ };
24141
+ }
24142
+ function getLegacyAuthScriptAddressByWIF(network, wif, options = {}) {
24143
+ const pqChain = getPQNetwork(network);
24144
+ const publicKeyHex = publicKeyHexFromWIF(wif);
24145
+ const publicKeyBytes = ensureBytes(publicKeyHex);
24146
+ const parts = authScriptCommitmentParts(0x02, publicKeyBytes, options);
24147
+ return {
24148
+ address: legacyAuthScriptToAddressBytes(publicKeyBytes, pqChain, options),
24149
+ publicKey: publicKeyHex,
24150
+ privateKey: "",
24151
+ WIF: wif,
24152
+ authType: 0x02,
24153
+ authDescriptor: bytesToHex(parts.authDescriptor),
24154
+ commitment: bytesToHex(parts.commitment),
24155
+ witnessScript: bytesToHex(parts.witnessScript),
24156
+ };
24157
+ }
24080
24158
  function getPQAddress(network, mnemonic, account, index, passphrase = "", options = {}) {
24081
24159
  const chain = getPQNetwork(network);
24082
24160
  const hdKey = getPQHDKey(network, mnemonic, passphrase);
@@ -24129,6 +24207,9 @@ zurdo`.split('\n');
24129
24207
  getPQAddress,
24130
24208
  getPQAddressByPath,
24131
24209
  getPQHDKey,
24210
+ getNoAuthAddress,
24211
+ getLegacyAuthScriptAddress,
24212
+ getLegacyAuthScriptAddressByWIF,
24132
24213
  pqPublicKeyToAddress,
24133
24214
  pqPublicKeyToAuthDescriptorHex,
24134
24215
  pqPublicKeyToCommitmentHex,