@neuraiproject/neurai-key 3.0.0 → 3.0.2
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 +35 -14
- package/dist/NeuraiKey.global.js +66 -14
- package/dist/NeuraiKey.global.js.map +1 -1
- package/dist/browser.js +67 -15
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +68 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +17 -6
- package/dist/index.js +67 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ 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 addresses using ML-DSA-44 (FIPS 204) with Bech32m encoding
|
|
19
|
+
- ✅ PostQuantum AuthScript addresses using ML-DSA-44 (FIPS 204) with Bech32m encoding
|
|
20
20
|
|
|
21
21
|
## Network Types
|
|
22
22
|
|
|
@@ -24,12 +24,12 @@ This library supports three Neurai network configurations:
|
|
|
24
24
|
|
|
25
25
|
- **`xna` / `xna-test`**: Current Neurai standard (BIP44 coin type: 1900)
|
|
26
26
|
- **`xna-legacy` / `xna-legacy-test`**: Legacy Neurai addresses (BIP44 coin type: 0)
|
|
27
|
-
- **`xna-pq` / `xna-pq-test`**: PostQuantum ML-DSA-44 addresses (Bech32m, witness v1)
|
|
27
|
+
- **`xna-pq` / `xna-pq-test`**: PostQuantum ML-DSA-44 AuthScript addresses (Bech32m, witness v1)
|
|
28
28
|
|
|
29
29
|
The main difference is the derivation path and address encoding:
|
|
30
|
-
- **XNA**: `m/44'/1900'/0'/0/0` — Base58Check
|
|
31
|
-
- **XNA Legacy**: `m/44'/0'/0'/0/0` — Base58Check
|
|
32
|
-
- **XNA PostQuantum**: `m/100'/1900'/0'/0/0` — Bech32m
|
|
30
|
+
- **XNA**: mainnet `m/44'/1900'/0'/0/0`, testnet `m/44'/1'/0'/0/0` — Base58Check (recommended for new wallets)
|
|
31
|
+
- **XNA Legacy**: mainnet `m/44'/0'/0'/0/0`, testnet `m/44'/1'/0'/0/0` — Base58Check (for compatibility with older wallets)
|
|
32
|
+
- **XNA PostQuantum**: mainnet `m/100'/1900'/0'/0/0`, testnet default/external `m/100'/1'/0'/0/0` — Bech32m (`nq1` / `tnq1`)
|
|
33
33
|
|
|
34
34
|
**Note**: Using different network types will generate completely different addresses from the same mnemonic.
|
|
35
35
|
|
|
@@ -181,9 +181,9 @@ console.log(testAddress); // tPXGaMRNwZuV1UKSrD9gABPscrJWUmedQ9
|
|
|
181
181
|
|
|
182
182
|
`publicKeyToAddress` throws if the key length is not 33 or 65 bytes so invalid inputs are surfaced immediately.
|
|
183
183
|
|
|
184
|
-
## PostQuantum (ML-DSA-44) Addresses
|
|
184
|
+
## PostQuantum (ML-DSA-44) AuthScript Addresses
|
|
185
185
|
|
|
186
|
-
Generate quantum-resistant addresses using the ML-DSA-44 signature scheme (FIPS 204).
|
|
186
|
+
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
187
|
|
|
188
188
|
### Generate a PQ address
|
|
189
189
|
|
|
@@ -199,15 +199,21 @@ const pqAddress = NeuraiKey.getPQAddress(network, mnemonic, ACCOUNT, INDEX);
|
|
|
199
199
|
console.log(pqAddress);
|
|
200
200
|
```
|
|
201
201
|
|
|
202
|
+
`getPQAddress()` returns the external branch by default.
|
|
203
|
+
|
|
202
204
|
Outputs
|
|
203
205
|
|
|
204
206
|
```
|
|
205
207
|
{
|
|
206
|
-
address: 'nq1...', // Bech32m address
|
|
208
|
+
address: 'nq1...', // Bech32m AuthScript address
|
|
209
|
+
authType: 1, // 0x01 = PQ single-key auth
|
|
210
|
+
authDescriptor: '01...', // 0x01 || HASH160(pq_pubkey)
|
|
211
|
+
commitment: '...', // tagged_hash("NeuraiAuthScript", ...)
|
|
207
212
|
path: "m/100'/1900'/0'/0/0", // PQ derivation path
|
|
208
213
|
publicKey: '...', // ML-DSA-44 public key (2624 hex chars = 1312 bytes)
|
|
209
214
|
privateKey: '...', // ML-DSA-44 private key (5120 hex chars = 2560 bytes)
|
|
210
|
-
seedKey: '...'
|
|
215
|
+
seedKey: '...', // 32-byte BIP32 seed used for ML-DSA keygen (64 hex chars)
|
|
216
|
+
witnessScript: '51' // default OP_TRUE script for simple PQ auth
|
|
211
217
|
}
|
|
212
218
|
```
|
|
213
219
|
|
|
@@ -227,6 +233,19 @@ const reconstructed = NeuraiKey.pqPublicKeyToAddress("xna-pq", pqAddress.publicK
|
|
|
227
233
|
// reconstructed === pqAddress.address
|
|
228
234
|
```
|
|
229
235
|
|
|
236
|
+
### Custom AuthScript witnessScript
|
|
237
|
+
|
|
238
|
+
```javascript
|
|
239
|
+
const pqAddress = NeuraiKey.getPQAddress("xna-pq", mnemonic, 0, 0, "", {
|
|
240
|
+
witnessScript: "5151"
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
console.log(pqAddress.witnessScript); // 5151
|
|
244
|
+
console.log(pqAddress.commitment); // new 32-byte commitment
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
`authType` no es configurable en la API pública. Esta librería genera únicamente direcciones PQ simples con `authType = 0x01`.
|
|
248
|
+
|
|
230
249
|
### Advanced: derive by path with HD key reuse
|
|
231
250
|
|
|
232
251
|
```javascript
|
|
@@ -235,20 +254,22 @@ const addr0 = NeuraiKey.getPQAddressByPath("xna-pq", hdKey, "m/100'/1900'/0'/0/0
|
|
|
235
254
|
const addr1 = NeuraiKey.getPQAddressByPath("xna-pq", hdKey, "m/100'/1900'/0'/0/1");
|
|
236
255
|
```
|
|
237
256
|
|
|
238
|
-
### PQ
|
|
257
|
+
### PQ AuthScript Details
|
|
239
258
|
|
|
240
259
|
| Property | Value |
|
|
241
260
|
|----------|-------|
|
|
242
261
|
| Signature algorithm | ML-DSA-44 (FIPS 204) |
|
|
243
|
-
| Address encoding | Bech32m (witness
|
|
262
|
+
| Address encoding | Bech32m (`witness v1` AuthScript) |
|
|
244
263
|
| Mainnet HRP / prefix | `nq` / `nq1...` |
|
|
245
264
|
| Testnet HRP / prefix | `tnq` / `tnq1...` |
|
|
246
265
|
| Public key size | 1312 bytes |
|
|
247
266
|
| Derivation path (mainnet) | `m/100'/1900'/0'/0/index` |
|
|
248
|
-
| Derivation path (testnet) | `m/100'/
|
|
249
|
-
|
|
|
267
|
+
| Derivation path (testnet default/external) | `m/100'/1'/account'/0/index` |
|
|
268
|
+
| Auth descriptor | `0x01 \|\| HASH160(pq_pubkey)` |
|
|
269
|
+
| Commitment | `tagged_hash("NeuraiAuthScript", 0x01 \|\| auth_descriptor \|\| SHA256(witnessScript))` |
|
|
270
|
+
| Default witnessScript | `OP_TRUE` (`51` in hex) |
|
|
250
271
|
|
|
251
|
-
**Note**: PQ addresses do not have a WIF (Wallet Import Format) field since WIF is specific to secp256k1 keys. The `seedKey` field contains the 32-byte BIP32-derived seed used for deterministic ML-DSA-44 key generation, useful for cross-implementation verification.
|
|
272
|
+
**Note**: PQ AuthScript addresses do not have a WIF (Wallet Import Format) field since WIF is specific to secp256k1 keys. The `seedKey` field contains the 32-byte BIP32-derived seed used for deterministic ML-DSA-44 key generation, useful for cross-implementation verification.
|
|
252
273
|
|
|
253
274
|
## Get public key from WIF
|
|
254
275
|
|
package/dist/NeuraiKey.global.js
CHANGED
|
@@ -21503,6 +21503,13 @@ zurdo`.split('\n');
|
|
|
21503
21503
|
function hash160(data) {
|
|
21504
21504
|
return ripemd160(sha256(data));
|
|
21505
21505
|
}
|
|
21506
|
+
function sha256Hash(data) {
|
|
21507
|
+
return sha256(data);
|
|
21508
|
+
}
|
|
21509
|
+
function taggedHash(tag, data) {
|
|
21510
|
+
const tagHash = sha256(utf8ToBytes(tag));
|
|
21511
|
+
return sha256(concatBytes(tagHash, tagHash, data));
|
|
21512
|
+
}
|
|
21506
21513
|
function doubleSha256(data) {
|
|
21507
21514
|
return sha256(sha256(data));
|
|
21508
21515
|
}
|
|
@@ -21543,7 +21550,6 @@ zurdo`.split('\n');
|
|
|
21543
21550
|
return Uint8Array.from(mnemonicToSeedSync(mnemonic, passphrase));
|
|
21544
21551
|
}
|
|
21545
21552
|
const BITCOIN_SEED_KEY = utf8ToBytes("Bitcoin seed");
|
|
21546
|
-
const HASH160_PREFIX = Uint8Array.from([0x05]);
|
|
21547
21553
|
|
|
21548
21554
|
/**
|
|
21549
21555
|
* Utils for modular division and fields.
|
|
@@ -23708,6 +23714,10 @@ zurdo`.split('\n');
|
|
|
23708
23714
|
|
|
23709
23715
|
var distExports = requireDist();
|
|
23710
23716
|
|
|
23717
|
+
const AUTHSCRIPT_TAG = "NeuraiAuthScript";
|
|
23718
|
+
const AUTHSCRIPT_VERSION = 0x01;
|
|
23719
|
+
const PQ_AUTH_TYPE = 0x01;
|
|
23720
|
+
const DEFAULT_WITNESS_SCRIPT = Uint8Array.from([0x51]);
|
|
23711
23721
|
function encodeWIF(privateKey, version, compressed = true) {
|
|
23712
23722
|
const payload = compressed
|
|
23713
23723
|
? concatBytes(Uint8Array.from([version]), privateKey, Uint8Array.from([0x01]))
|
|
@@ -23764,9 +23774,29 @@ zurdo`.split('\n');
|
|
|
23764
23774
|
function bech32mEncode(hrp, witnessVersion, hash) {
|
|
23765
23775
|
return distExports.bech32m.encode(hrp, [witnessVersion, ...distExports.bech32m.toWords(hash)]);
|
|
23766
23776
|
}
|
|
23767
|
-
function
|
|
23768
|
-
|
|
23769
|
-
|
|
23777
|
+
function normalizeWitnessScript(input) {
|
|
23778
|
+
return input ? ensureBytes(input) : Uint8Array.from(DEFAULT_WITNESS_SCRIPT);
|
|
23779
|
+
}
|
|
23780
|
+
function pqPublicKeyToAuthDescriptor(publicKey) {
|
|
23781
|
+
return concatBytes(Uint8Array.from([PQ_AUTH_TYPE]), hash160(publicKey));
|
|
23782
|
+
}
|
|
23783
|
+
function pqPublicKeyToCommitment(publicKey, options = {}) {
|
|
23784
|
+
return pqPublicKeyToCommitmentParts(publicKey, options).commitment;
|
|
23785
|
+
}
|
|
23786
|
+
function pqPublicKeyToCommitmentParts(publicKey, options = {}) {
|
|
23787
|
+
const witnessScript = normalizeWitnessScript(options.witnessScript);
|
|
23788
|
+
const authDescriptor = pqPublicKeyToAuthDescriptor(publicKey);
|
|
23789
|
+
const witnessScriptHash = sha256Hash(witnessScript);
|
|
23790
|
+
const commitment = taggedHash(AUTHSCRIPT_TAG, concatBytes(Uint8Array.from([AUTHSCRIPT_VERSION]), authDescriptor, witnessScriptHash));
|
|
23791
|
+
return {
|
|
23792
|
+
authDescriptor,
|
|
23793
|
+
authType: PQ_AUTH_TYPE,
|
|
23794
|
+
commitment,
|
|
23795
|
+
witnessScript,
|
|
23796
|
+
};
|
|
23797
|
+
}
|
|
23798
|
+
function pqPublicKeyToAddressBytes(publicKey, network, options = {}) {
|
|
23799
|
+
return bech32mEncode(network.hrp, network.witnessVersion, pqPublicKeyToCommitment(publicKey, options));
|
|
23770
23800
|
}
|
|
23771
23801
|
function normalizePublicKey(input) {
|
|
23772
23802
|
return ensureBytes(input);
|
|
@@ -23928,8 +23958,8 @@ zurdo`.split('\n');
|
|
|
23928
23958
|
hrp: "tnq",
|
|
23929
23959
|
witnessVersion: 1,
|
|
23930
23960
|
purpose: 100,
|
|
23931
|
-
coinType:
|
|
23932
|
-
changeIndex:
|
|
23961
|
+
coinType: 1,
|
|
23962
|
+
changeIndex: 0,
|
|
23933
23963
|
bip32: { private: 70615956, public: 70617039 },
|
|
23934
23964
|
},
|
|
23935
23965
|
};
|
|
@@ -24026,7 +24056,7 @@ zurdo`.split('\n');
|
|
|
24026
24056
|
const seed = mnemonicToSeedBytes(mnemonicToSeedSync, mnemonic, passphrase);
|
|
24027
24057
|
return HDKey.fromMasterSeed(seed, chain.bip32);
|
|
24028
24058
|
}
|
|
24029
|
-
function getPQAddressByPath(network, hdKey, path) {
|
|
24059
|
+
function getPQAddressByPath(network, hdKey, path, options = {}) {
|
|
24030
24060
|
const chain = getPQNetwork(network);
|
|
24031
24061
|
const derived = hdKey.derive(path);
|
|
24032
24062
|
if (!derived.privateKey) {
|
|
@@ -24034,30 +24064,50 @@ zurdo`.split('\n');
|
|
|
24034
24064
|
}
|
|
24035
24065
|
const seed32 = Uint8Array.from(derived.privateKey);
|
|
24036
24066
|
const { publicKey, secretKey } = ml_dsa44.keygen(seed32);
|
|
24067
|
+
const authScript = pqPublicKeyToCommitmentParts(publicKey, options);
|
|
24037
24068
|
return {
|
|
24038
|
-
address: pqPublicKeyToAddressBytes(publicKey, chain),
|
|
24069
|
+
address: pqPublicKeyToAddressBytes(publicKey, chain, options),
|
|
24070
|
+
authType: authScript.authType,
|
|
24071
|
+
authDescriptor: bytesToHex(authScript.authDescriptor),
|
|
24072
|
+
commitment: bytesToHex(authScript.commitment),
|
|
24039
24073
|
path,
|
|
24040
24074
|
publicKey: bytesToHex(publicKey),
|
|
24041
24075
|
privateKey: bytesToHex(secretKey),
|
|
24042
24076
|
seedKey: bytesToHex(seed32),
|
|
24077
|
+
witnessScript: bytesToHex(authScript.witnessScript),
|
|
24043
24078
|
};
|
|
24044
24079
|
}
|
|
24045
|
-
function getPQAddress(network, mnemonic, account, index, passphrase = "") {
|
|
24080
|
+
function getPQAddress(network, mnemonic, account, index, passphrase = "", options = {}) {
|
|
24046
24081
|
const chain = getPQNetwork(network);
|
|
24047
24082
|
const hdKey = getPQHDKey(network, mnemonic, passphrase);
|
|
24048
24083
|
const path = `m/${chain.purpose}'/${chain.coinType}'/${account}'/${chain.changeIndex}/${index}`;
|
|
24049
|
-
return getPQAddressByPath(network, hdKey, path);
|
|
24084
|
+
return getPQAddressByPath(network, hdKey, path, options);
|
|
24085
|
+
}
|
|
24086
|
+
function pqPublicKeyToAddress(network, publicKey, options = {}) {
|
|
24087
|
+
const keyBytes = ensureBytes(publicKey);
|
|
24088
|
+
if (keyBytes.length !== 1312) {
|
|
24089
|
+
throw new Error("ML-DSA-44 public key must be 1312 bytes");
|
|
24090
|
+
}
|
|
24091
|
+
normalizeWitnessScript(options.witnessScript);
|
|
24092
|
+
return pqPublicKeyToAddressBytes(keyBytes, getPQNetwork(network), options);
|
|
24093
|
+
}
|
|
24094
|
+
function pqPublicKeyToCommitmentHex(publicKey, options = {}) {
|
|
24095
|
+
const keyBytes = ensureBytes(publicKey);
|
|
24096
|
+
if (keyBytes.length !== 1312) {
|
|
24097
|
+
throw new Error("ML-DSA-44 public key must be 1312 bytes");
|
|
24098
|
+
}
|
|
24099
|
+
return bytesToHex(pqPublicKeyToCommitment(keyBytes, options));
|
|
24050
24100
|
}
|
|
24051
|
-
function
|
|
24101
|
+
function pqPublicKeyToAuthDescriptorHex(publicKey) {
|
|
24052
24102
|
const keyBytes = ensureBytes(publicKey);
|
|
24053
24103
|
if (keyBytes.length !== 1312) {
|
|
24054
24104
|
throw new Error("ML-DSA-44 public key must be 1312 bytes");
|
|
24055
24105
|
}
|
|
24056
|
-
return
|
|
24106
|
+
return bytesToHex(pqPublicKeyToAuthDescriptor(keyBytes));
|
|
24057
24107
|
}
|
|
24058
|
-
function generatePQAddressObject(network = "xna-pq", passphrase = "") {
|
|
24108
|
+
function generatePQAddressObject(network = "xna-pq", passphrase = "", options = {}) {
|
|
24059
24109
|
const mnemonic = generateMnemonic();
|
|
24060
|
-
const addressObj = getPQAddress(network, mnemonic, 0, 0, passphrase);
|
|
24110
|
+
const addressObj = getPQAddress(network, mnemonic, 0, 0, passphrase, options);
|
|
24061
24111
|
return {
|
|
24062
24112
|
...addressObj,
|
|
24063
24113
|
mnemonic,
|
|
@@ -24080,6 +24130,8 @@ zurdo`.split('\n');
|
|
|
24080
24130
|
getPQAddressByPath,
|
|
24081
24131
|
getPQHDKey,
|
|
24082
24132
|
pqPublicKeyToAddress,
|
|
24133
|
+
pqPublicKeyToAuthDescriptorHex,
|
|
24134
|
+
pqPublicKeyToCommitmentHex,
|
|
24083
24135
|
generatePQAddressObject,
|
|
24084
24136
|
};
|
|
24085
24137
|
|