@btc-vision/transaction 1.7.0 → 1.7.1

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.
@@ -0,0 +1,307 @@
1
+ # Address Verification Guide
2
+
3
+ ## Table of Contents
4
+ - [ML-DSA Public Key Validation](#ml-dsa-public-key-validation)
5
+ - [Address Type Detection](#address-type-detection)
6
+ - [Classical Address Validation](#classical-address-validation)
7
+ - [Complete Validation Example](#complete-validation-example)
8
+
9
+ ## ML-DSA Public Key Validation
10
+
11
+ ### Validating ML-DSA Public Keys
12
+
13
+ The `AddressVerificator` provides methods to validate ML-DSA public keys and determine their security level:
14
+
15
+ ```typescript
16
+ import { AddressVerificator, MLDSASecurityLevel } from '@btc-vision/transaction';
17
+
18
+ // Valid ML-DSA-44 public key (1312 bytes)
19
+ const level2Key = Buffer.alloc(1312);
20
+ const level2Check = AddressVerificator.isValidMLDSAPublicKey(level2Key);
21
+ console.log('LEVEL2 valid:', level2Check); // MLDSASecurityLevel.LEVEL2
22
+
23
+ // Valid ML-DSA-65 public key (1952 bytes)
24
+ const level3Key = Buffer.alloc(1952);
25
+ const level3Check = AddressVerificator.isValidMLDSAPublicKey(level3Key);
26
+ console.log('LEVEL3 valid:', level3Check); // MLDSASecurityLevel.LEVEL3
27
+
28
+ // Valid ML-DSA-87 public key (2592 bytes)
29
+ const level5Key = Buffer.alloc(2592);
30
+ const level5Check = AddressVerificator.isValidMLDSAPublicKey(level5Key);
31
+ console.log('LEVEL5 valid:', level5Check); // MLDSASecurityLevel.LEVEL5
32
+
33
+ // Invalid length
34
+ const invalidKey = Buffer.alloc(1000);
35
+ const invalidCheck = AddressVerificator.isValidMLDSAPublicKey(invalidKey);
36
+ console.log('Invalid:', invalidCheck); // null
37
+ ```
38
+
39
+ ### Input Format Support
40
+
41
+ Validation supports multiple input formats:
42
+
43
+ ```typescript
44
+ import { AddressVerificator, MLDSASecurityLevel } from '@btc-vision/transaction';
45
+
46
+ // Hex string (with 0x prefix)
47
+ const hexWith0x = '0x' + 'a'.repeat(2624); // 1312 bytes in hex
48
+ const check1 = AddressVerificator.isValidMLDSAPublicKey(hexWith0x);
49
+ console.log('Hex with 0x:', check1); // MLDSASecurityLevel.LEVEL2
50
+
51
+ // Hex string (without 0x prefix)
52
+ const hexWithout0x = 'a'.repeat(2624);
53
+ const check2 = AddressVerificator.isValidMLDSAPublicKey(hexWithout0x);
54
+ console.log('Hex without 0x:', check2); // MLDSASecurityLevel.LEVEL2
55
+
56
+ // Buffer
57
+ const buffer = Buffer.alloc(1312);
58
+ const check3 = AddressVerificator.isValidMLDSAPublicKey(buffer);
59
+ console.log('Buffer:', check3); // MLDSASecurityLevel.LEVEL2
60
+
61
+ // Uint8Array
62
+ const uint8Array = new Uint8Array(1312);
63
+ const check4 = AddressVerificator.isValidMLDSAPublicKey(uint8Array);
64
+ console.log('Uint8Array:', check4); // MLDSASecurityLevel.LEVEL2
65
+ ```
66
+
67
+ ### Validating Wallet Keys
68
+
69
+ ```typescript
70
+ import { Mnemonic, AddressVerificator, MLDSASecurityLevel } from '@btc-vision/transaction';
71
+ import { networks } from '@btc-vision/bitcoin';
72
+
73
+ // Generate wallet
74
+ const mnemonic = Mnemonic.generate(undefined, '', networks.bitcoin, MLDSASecurityLevel.LEVEL2);
75
+ const wallet = mnemonic.derive(0);
76
+
77
+ // Validate quantum public key
78
+ const quantumKeyHex = wallet.quantumPublicKeyHex;
79
+ const securityLevel = AddressVerificator.isValidMLDSAPublicKey(quantumKeyHex);
80
+
81
+ console.log('Quantum key valid:', securityLevel !== null);
82
+ console.log('Security level:', securityLevel); // MLDSASecurityLevel.LEVEL2
83
+ console.log('Expected:', wallet.securityLevel); // MLDSASecurityLevel.LEVEL2
84
+ console.log('Match:', securityLevel === wallet.securityLevel); // true
85
+ ```
86
+
87
+ ### Error Cases
88
+
89
+ ```typescript
90
+ // Empty string
91
+ console.log(AddressVerificator.isValidMLDSAPublicKey('')); // null
92
+
93
+ // Empty Buffer
94
+ console.log(AddressVerificator.isValidMLDSAPublicKey(Buffer.alloc(0))); // null
95
+
96
+ // Invalid hex
97
+ console.log(AddressVerificator.isValidMLDSAPublicKey('not hex')); // null
98
+
99
+ // Wrong length (classical key size)
100
+ const classicalKey = Buffer.alloc(33);
101
+ console.log(AddressVerificator.isValidMLDSAPublicKey(classicalKey)); // null
102
+
103
+ // Wrong length (arbitrary size)
104
+ const wrongSize = Buffer.alloc(1500);
105
+ console.log(AddressVerificator.isValidMLDSAPublicKey(wrongSize)); // null
106
+ ```
107
+
108
+ ## Address Type Detection
109
+
110
+ ### Detecting Address Types
111
+
112
+ ```typescript
113
+ import { AddressVerificator, AddressTypes } from '@btc-vision/transaction';
114
+ import { networks } from '@btc-vision/bitcoin';
115
+
116
+ const wallet = mnemonic.derive(0);
117
+
118
+ // P2TR Detection
119
+ const p2tr = wallet.p2tr;
120
+ const p2trType = AddressVerificator.detectAddressType(p2tr, networks.bitcoin);
121
+ console.log('P2TR type:', p2trType); // AddressTypes.P2TR
122
+
123
+ // P2WPKH Detection
124
+ const p2wpkh = wallet.p2wpkh;
125
+ const p2wpkhType = AddressVerificator.detectAddressType(p2wpkh, networks.bitcoin);
126
+ console.log('P2WPKH type:', p2wpkhType); // AddressTypes.P2WPKH
127
+
128
+ // P2PKH Detection
129
+ const p2pkh = wallet.p2pkh;
130
+ const p2pkhType = AddressVerificator.detectAddressType(p2pkh, networks.bitcoin);
131
+ console.log('P2PKH type:', p2pkhType); // AddressTypes.P2PKH
132
+ ```
133
+
134
+ ### Available Address Types
135
+
136
+ ```typescript
137
+ enum AddressTypes {
138
+ P2PKH = 'P2PKH', // Legacy (1...)
139
+ P2SH_OR_P2SH_P2WPKH = 'P2SH_OR_P2SH-P2WPKH', // Script hash (3...)
140
+ P2PK = 'P2PK', // Public key
141
+ P2TR = 'P2TR', // Taproot (bc1p...)
142
+ P2WPKH = 'P2WPKH', // SegWit (bc1q...)
143
+ P2WSH = 'P2WSH', // SegWit script (bc1q...)
144
+ P2WDA = 'P2WDA', // Witness data auth
145
+ }
146
+ ```
147
+
148
+ ### Distinguishing Similar Addresses
149
+
150
+ ```typescript
151
+ const wallet = mnemonic.derive(0);
152
+
153
+ // P2TR vs P2WPKH (both Bech32 formats)
154
+ const p2tr = wallet.p2tr;
155
+ const p2wpkh = wallet.p2wpkh;
156
+
157
+ const p2trType = AddressVerificator.detectAddressType(p2tr, networks.bitcoin);
158
+ const p2wpkhType = AddressVerificator.detectAddressType(p2wpkh, networks.bitcoin);
159
+
160
+ console.log('P2TR detected as:', p2trType); // AddressTypes.P2TR
161
+ console.log('P2WPKH detected as:', p2wpkhType); // AddressTypes.P2WPKH
162
+ console.log('Different types:', p2trType !== p2wpkhType); // true
163
+ ```
164
+
165
+ ### Network-Specific Detection
166
+
167
+ ```typescript
168
+ // Mainnet address on mainnet
169
+ const mainnetAddr = wallet.p2tr;
170
+ const mainnetDetect = AddressVerificator.detectAddressType(mainnetAddr, networks.bitcoin);
171
+ console.log('Mainnet on mainnet:', mainnetDetect); // AddressTypes.P2TR
172
+
173
+ // Mainnet address on wrong network
174
+ const wrongNetwork = AddressVerificator.detectAddressType(mainnetAddr, networks.testnet);
175
+ console.log('Mainnet on testnet:', wrongNetwork); // null
176
+ ```
177
+
178
+ ## Classical Address Validation
179
+
180
+ ### Validating Classical Public Keys
181
+
182
+ ```typescript
183
+ import { AddressVerificator } from '@btc-vision/transaction';
184
+ import { networks } from '@btc-vision/bitcoin';
185
+
186
+ const wallet = mnemonic.derive(0);
187
+
188
+ // Validate compressed public key (33 bytes)
189
+ const compressedKey = wallet.toPublicKeyHex();
190
+ const isValid = AddressVerificator.isValidPublicKey(compressedKey, networks.bitcoin);
191
+ console.log('Compressed key valid:', isValid); // true
192
+
193
+ // Validate uncompressed public key (65 bytes)
194
+ const uncompressedKey = wallet.toUncompressedPublicKey().toString('hex');
195
+ const isUncompressedValid = AddressVerificator.isValidPublicKey(uncompressedKey, networks.bitcoin);
196
+ console.log('Uncompressed key valid:', isUncompressedValid); // true
197
+ ```
198
+
199
+ ### Validating Other Address Types
200
+
201
+ ```typescript
202
+ // P2TR validation
203
+ const p2tr = wallet.p2tr;
204
+ const isP2TRValid = AddressVerificator.isValidP2TRAddress(p2tr, networks.bitcoin);
205
+ console.log('P2TR valid:', isP2TRValid); // true
206
+
207
+ // P2WPKH validation
208
+ const p2wpkh = wallet.p2wpkh;
209
+ const isP2WPKHValid = AddressVerificator.isP2WPKHAddress(p2wpkh, networks.bitcoin);
210
+ console.log('P2WPKH valid:', isP2WPKHValid); // true
211
+
212
+ // P2PKH or P2SH validation
213
+ const p2pkh = wallet.p2pkh;
214
+ const isLegacyValid = AddressVerificator.isP2PKHOrP2SH(p2pkh, networks.bitcoin);
215
+ console.log('Legacy valid:', isLegacyValid); // true
216
+ ```
217
+
218
+ ## Complete Validation Example
219
+
220
+ ```typescript
221
+ import {
222
+ Mnemonic,
223
+ AddressVerificator,
224
+ AddressTypes,
225
+ MLDSASecurityLevel,
226
+ } from '@btc-vision/transaction';
227
+ import { networks } from '@btc-vision/bitcoin';
228
+
229
+ // Generate wallet
230
+ const mnemonic = Mnemonic.generate(undefined, '', networks.bitcoin, MLDSASecurityLevel.LEVEL2);
231
+ const wallet = mnemonic.derive(0);
232
+
233
+ console.log('=== ML-DSA Public Key Validation ===');
234
+
235
+ // Validate quantum public key
236
+ const quantumKeyHex = wallet.quantumPublicKeyHex;
237
+ const quantumKeyBuffer = wallet.quantumPublicKey;
238
+
239
+ const securityLevelFromHex = AddressVerificator.isValidMLDSAPublicKey(quantumKeyHex);
240
+ const securityLevelFromBuffer = AddressVerificator.isValidMLDSAPublicKey(quantumKeyBuffer);
241
+
242
+ console.log('Hex validation:', securityLevelFromHex); // MLDSASecurityLevel.LEVEL2
243
+ console.log('Buffer validation:', securityLevelFromBuffer); // MLDSASecurityLevel.LEVEL2
244
+ console.log('Matches wallet:', securityLevelFromHex === wallet.securityLevel); // true
245
+
246
+ console.log('\n=== Address Type Detection ===');
247
+
248
+ // Detect all address types
249
+ const addresses = {
250
+ p2tr: wallet.p2tr,
251
+ p2wpkh: wallet.p2wpkh,
252
+ p2pkh: wallet.p2pkh,
253
+ };
254
+
255
+ for (const [name, addr] of Object.entries(addresses)) {
256
+ const type = AddressVerificator.detectAddressType(addr, networks.bitcoin);
257
+ console.log(`${name}: ${type}`);
258
+ }
259
+
260
+ console.log('\n=== Classical Key Validation ===');
261
+
262
+ // Validate classical public key
263
+ const classicalKey = wallet.toPublicKeyHex();
264
+ const isClassicalValid = AddressVerificator.isValidPublicKey(classicalKey, networks.bitcoin);
265
+
266
+ console.log('Classical key:', classicalKey);
267
+ console.log('Classical valid:', isClassicalValid); // true
268
+
269
+ console.log('\n=== Cross-Network Validation ===');
270
+
271
+ // Test network mismatch
272
+ const mainnetP2TR = wallet.p2tr;
273
+ const testnetMnemonic = Mnemonic.generate(undefined, '', networks.testnet, MLDSASecurityLevel.LEVEL2);
274
+ const testnetWallet = testnetMnemonic.derive(0);
275
+ const testnetP2TR = testnetWallet.p2tr;
276
+
277
+ const mainnetType = AddressVerificator.detectAddressType(mainnetP2TR, networks.bitcoin);
278
+ const wrongNetworkType = AddressVerificator.detectAddressType(mainnetP2TR, networks.testnet);
279
+
280
+ console.log('Mainnet P2TR on mainnet:', mainnetType); // AddressTypes.P2TR
281
+ console.log('Mainnet P2TR on testnet:', wrongNetworkType); // null
282
+
283
+ console.log('\n=== Complete Wallet Validation ===');
284
+
285
+ function validateWallet(wallet: any, network: any): boolean {
286
+ // Validate quantum key
287
+ const quantumValid = AddressVerificator.isValidMLDSAPublicKey(
288
+ wallet.quantumPublicKey
289
+ ) !== null;
290
+
291
+ // Validate classical key
292
+ const classicalValid = AddressVerificator.isValidPublicKey(
293
+ wallet.toPublicKeyHex(),
294
+ network
295
+ );
296
+
297
+ return quantumValid && classicalValid;
298
+ }
299
+
300
+ const isWalletValid = validateWallet(wallet, networks.bitcoin);
301
+ console.log('Complete wallet validation:', isWalletValid); // true
302
+ ```
303
+
304
+ ## Next Steps
305
+
306
+ - [Message Signing](./04-message-signing.md) - Sign and verify messages
307
+ - [Introduction](./01-introduction.md) - Back to overview
@@ -0,0 +1,65 @@
1
+ # OPNet ML-DSA Quantum Support Documentation
2
+
3
+ Welcome to the OPNet ML-DSA (Post-Quantum Cryptography) documentation! This guide will help you integrate quantum-resistant signatures and addresses into your OPNet applications.
4
+
5
+ ## Documentation Index
6
+
7
+ ### [1. Introduction to ML-DSA](./01-introduction.md)
8
+ Learn about ML-DSA (Module-Lattice-Based Digital Signature Algorithm), the hybrid quantum-classical architecture, and when to use quantum-resistant cryptography.
9
+
10
+ **Topics covered:**
11
+ - What is ML-DSA and post-quantum cryptography
12
+ - Three security levels: **LEVEL2 (BIP360 RECOMMENDED DEFAULT)**, LEVEL3, LEVEL5
13
+ - Hybrid classical + quantum architecture
14
+ - Quick start guide
15
+ - When to use ML-DSA vs classical crypto
16
+
17
+ ### [2. Mnemonic & Wallet Management](./02-mnemonic-and-wallet.md)
18
+ Complete guide to generating and managing quantum-resistant wallets using BIP39 mnemonics and BIP360 quantum key derivation.
19
+
20
+ **Topics covered:**
21
+ - Generating new mnemonics with quantum support
22
+ - Loading existing mnemonics
23
+ - Deriving wallets (single and multiple)
24
+ - Wallet properties (classical and quantum keys)
25
+ - Security best practices
26
+ - Network awareness
27
+ - Advanced usage
28
+
29
+ ### [3. Address Generation](./03-address-generation.md)
30
+ Learn to generate P2OP and classical Bitcoin addresses for all networks.
31
+
32
+ **Topics covered:**
33
+ - P2OP addresses (Pay-to-OPNet, for contract addresses)
34
+ - Classical addresses (P2TR, P2WPKH, P2PKH, P2SH)
35
+ - P2WDA (Witness Data Authentication)
36
+ - Network support (mainnet, testnet, regtest)
37
+ - Address comparison and ordering
38
+ - Time-locked addresses (CSV)
39
+ - Address caching
40
+
41
+ ### [4. Message Signing](./04-message-signing.md)
42
+ Sign and verify messages using ML-DSA (quantum) and Schnorr (classical) signatures. Includes detailed explanation of `QuantumBIP32Factory.fromPublicKey()` usage for signature verification.
43
+
44
+ **Topics covered:**
45
+ - ML-DSA message signing and verification
46
+ - Schnorr message signing
47
+ - Multiple input formats (string, Buffer, Uint8Array, hex)
48
+ - Cross-format verification
49
+ - Tweaked signatures for Taproot
50
+ - Message hashing (SHA-256)
51
+ - Best practices
52
+
53
+ ### [5. Address Verification](./05-address-verification.md)
54
+ Validate ML-DSA public keys and detect classical address types.
55
+
56
+ **Topics covered:**
57
+ - ML-DSA public key validation
58
+ - Address type detection
59
+ - Classical address validation
60
+ - Network-specific validation
61
+ - Complete validation examples
62
+
63
+ ---
64
+
65
+ **Ready to get started?** Begin with the [Introduction](./01-introduction.md)!
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@btc-vision/transaction",
3
3
  "type": "module",
4
- "version": "1.7.0",
4
+ "version": "1.7.1",
5
5
  "author": "BlobMaster41",
6
6
  "description": "OPNet transaction library allows you to create and sign transactions for the OPNet network.",
7
7
  "engines": {
package/src/_version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '1.7.0';
1
+ export const version = '1.7.1';
@@ -0,0 +1,92 @@
1
+ /**
2
+ * BIP (Bitcoin Improvement Proposal) derivation path standards
3
+ *
4
+ * These define standardized derivation paths for different address types
5
+ * in hierarchical deterministic (HD) wallets.
6
+ *
7
+ * @see https://github.com/bitcoin/bips
8
+ */
9
+ export enum BIPStandard {
10
+ /**
11
+ * BIP44: Multi-Account Hierarchy for Deterministic Wallets
12
+ *
13
+ * Path: m/44'/coin_type'/account'/change/address_index
14
+ * Original standard for P2PKH (legacy) addresses
15
+ * Widely used by wallets like Unisat for all address types
16
+ *
17
+ * @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
18
+ */
19
+ BIP44 = 44,
20
+
21
+ /**
22
+ * BIP49: Derivation scheme for P2WPKH-nested-in-P2SH based accounts
23
+ *
24
+ * Path: m/49'/coin_type'/account'/change/address_index
25
+ * For wrapped SegWit addresses (P2SH-P2WPKH starting with '3')
26
+ *
27
+ * @see https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki
28
+ */
29
+ BIP49 = 49,
30
+
31
+ /**
32
+ * BIP84: Derivation scheme for P2WPKH based accounts
33
+ *
34
+ * Path: m/84'/coin_type'/account'/change/address_index
35
+ * For native SegWit addresses (P2WPKH starting with 'bc1q')
36
+ * DEFAULT for this library
37
+ *
38
+ * @see https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki
39
+ */
40
+ BIP84 = 84,
41
+
42
+ /**
43
+ * BIP86: Derivation scheme for P2TR based accounts
44
+ *
45
+ * Path: m/86'/coin_type'/account'/change/address_index
46
+ * For Taproot addresses (P2TR starting with 'bc1p')
47
+ *
48
+ * @see https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki
49
+ */
50
+ BIP86 = 86,
51
+ }
52
+
53
+ /**
54
+ * Get a human-readable description of a BIP standard
55
+ *
56
+ * @param standard - The BIP standard
57
+ * @returns A description of the standard and its typical use case
58
+ */
59
+ export function getBIPDescription(standard: BIPStandard): string {
60
+ switch (standard) {
61
+ case BIPStandard.BIP44:
62
+ return 'BIP44: Legacy addresses (P2PKH), widely used by Unisat and other wallets';
63
+ case BIPStandard.BIP49:
64
+ return 'BIP49: Wrapped SegWit addresses (P2SH-P2WPKH)';
65
+ case BIPStandard.BIP84:
66
+ return 'BIP84: Native SegWit addresses (P2WPKH) - DEFAULT';
67
+ case BIPStandard.BIP86:
68
+ return 'BIP86: Taproot addresses (P2TR)';
69
+ default:
70
+ return 'Unknown BIP standard';
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Build a derivation path for a given BIP standard
76
+ *
77
+ * @param standard - The BIP standard to use
78
+ * @param coinType - The coin type (0 for mainnet, 1 for testnet/regtest)
79
+ * @param account - The account index
80
+ * @param change - The change index (0 for receiving, 1 for change)
81
+ * @param addressIndex - The address index
82
+ * @returns The full derivation path
83
+ */
84
+ export function buildBIPPath(
85
+ standard: BIPStandard,
86
+ coinType: number,
87
+ account: number,
88
+ change: number,
89
+ addressIndex: number,
90
+ ): string {
91
+ return `m/${standard}'/${coinType}'/${account}'/${change}/${addressIndex}`;
92
+ }
@@ -10,11 +10,15 @@ import * as ecc from '@bitcoinerlab/secp256k1';
10
10
  import { initEccLib, Network, networks } from '@btc-vision/bitcoin';
11
11
  import { Wallet } from '../keypair/Wallet.js';
12
12
  import { MnemonicStrength } from './MnemonicStrength.js';
13
+ import { BIPStandard, buildBIPPath } from './BIPStandard.js';
14
+ import { AddressTypes } from '../keypair/AddressVerificator.js';
13
15
 
14
16
  initEccLib(ecc);
15
17
 
16
18
  const bip32 = BIP32Factory(ecc);
17
19
 
20
+ export { BIPStandard, getBIPDescription } from './BIPStandard.js';
21
+
18
22
  /**
19
23
  * Mnemonic class for managing BIP39 mnemonic phrases with BIP360 quantum support
20
24
  *
@@ -189,7 +193,7 @@ export class Mnemonic {
189
193
  }
190
194
 
191
195
  /**
192
- * Derive a wallet at a specific index using BIP360 (quantum) and BIP84 (classical) paths
196
+ * Derive a wallet at a specific index using BIP360 (quantum) and configurable BIP standard (classical) paths
193
197
  *
194
198
  * This method derives both classical ECDSA/Schnorr keys and quantum-resistant ML-DSA keys
195
199
  * for the wallet, providing hybrid post-quantum security.
@@ -197,11 +201,29 @@ export class Mnemonic {
197
201
  * @param index - The address index to derive (default: 0)
198
202
  * @param account - The account index (default: 0)
199
203
  * @param isChange - Whether this is a change address (default: false)
204
+ * @param bipStandard - The BIP standard to use for classical derivation (default: BIP84)
200
205
  * @returns A Wallet instance with both classical and quantum keys
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * // Default: BIP84 (Native SegWit)
210
+ * const wallet1 = mnemonic.derive(0);
211
+ *
212
+ * // BIP44 (Compatible with Unisat)
213
+ * const wallet2 = mnemonic.derive(0, 0, false, BIPStandard.BIP44);
214
+ *
215
+ * // BIP86 (Taproot)
216
+ * const wallet3 = mnemonic.derive(0, 0, false, BIPStandard.BIP86);
217
+ * ```
201
218
  */
202
- public derive(index: number = 0, account: number = 0, isChange: boolean = false): Wallet {
203
- // Derive classical key using BIP84 (Native SegWit)
204
- const classicalPath = this.buildClassicalPath(account, index, isChange);
219
+ public derive(
220
+ index: number = 0,
221
+ account: number = 0,
222
+ isChange: boolean = false,
223
+ bipStandard: BIPStandard = BIPStandard.BIP84,
224
+ ): Wallet {
225
+ // Derive classical key using specified BIP standard
226
+ const classicalPath = this.buildClassicalPath(account, index, isChange, bipStandard);
205
227
  const classicalChild = this._classicalRoot.derivePath(classicalPath);
206
228
 
207
229
  if (!classicalChild.privateKey) {
@@ -225,6 +247,101 @@ export class Mnemonic {
225
247
  );
226
248
  }
227
249
 
250
+ /**
251
+ * Derive a Unisat-compatible wallet
252
+ *
253
+ * Unisat uses different derivation paths based on address type:
254
+ * - Legacy (P2PKH): m/44'/coinType'/account'/change/index
255
+ * - Nested SegWit (P2SH-P2WPKH): m/49'/coinType'/account'/change/index
256
+ * - Native SegWit (P2WPKH): m/84'/coinType'/account'/change/index
257
+ * - Taproot (P2TR): m/86'/coinType'/account'/change/index
258
+ *
259
+ * @param addressType - The address type to generate
260
+ * @param index - The address index (default: 0)
261
+ * @param account - The account index (default: 0)
262
+ * @param isChange - Whether this is a change address (default: false)
263
+ * @returns A Wallet instance with both classical and quantum keys
264
+ */
265
+ public deriveUnisat(
266
+ addressType: AddressTypes = AddressTypes.P2TR,
267
+ index: number = 0,
268
+ account: number = 0,
269
+ isChange: boolean = false,
270
+ ): Wallet {
271
+ // Determine BIP purpose based on address type
272
+ let purpose: number;
273
+ switch (addressType) {
274
+ case AddressTypes.P2PKH:
275
+ purpose = 44;
276
+ break;
277
+ case AddressTypes.P2SH_OR_P2SH_P2WPKH:
278
+ purpose = 49;
279
+ break;
280
+ case AddressTypes.P2WPKH:
281
+ purpose = 84;
282
+ break;
283
+ case AddressTypes.P2TR:
284
+ purpose = 86;
285
+ break;
286
+ default:
287
+ throw new Error(`Unsupported address type: ${addressType}`);
288
+ }
289
+
290
+ // Build classical derivation path for Unisat
291
+ const coinType = this.getCoinType();
292
+ const change = isChange ? 1 : 0;
293
+ const classicalPath = `m/${purpose}'/0'/${account}'/${change}/${index}`;
294
+
295
+ // Derive classical key
296
+ const classicalChild = this._classicalRoot.derivePath(classicalPath);
297
+
298
+ if (!classicalChild.privateKey) {
299
+ throw new Error(`Failed to derive classical private key at path ${classicalPath}`);
300
+ }
301
+
302
+ // Derive quantum key using BIP360
303
+ const quantumPath = `m/360'/${coinType}'/${account}'/${change}/${index}`;
304
+ const quantumChild = this._quantumRoot.derivePath(quantumPath);
305
+
306
+ if (!quantumChild.privateKey) {
307
+ throw new Error(`Failed to derive quantum private key at path ${quantumPath}`);
308
+ }
309
+
310
+ // Create wallet with both classical and quantum keys
311
+ return new Wallet(
312
+ Buffer.from(classicalChild.privateKey).toString('hex'),
313
+ Buffer.from(quantumChild.privateKey).toString('hex'),
314
+ this._network,
315
+ this._securityLevel,
316
+ );
317
+ }
318
+
319
+ /**
320
+ * Derive multiple Unisat-compatible wallets
321
+ *
322
+ * @param addressType - The address type to generate
323
+ * @param count - Number of wallets to derive
324
+ * @param startIndex - Starting index (default: 0)
325
+ * @param account - The account index (default: 0)
326
+ * @param isChange - Whether these are change addresses (default: false)
327
+ * @returns Array of Wallet instances
328
+ */
329
+ public deriveMultipleUnisat(
330
+ addressType: AddressTypes = AddressTypes.P2TR,
331
+ count: number = 5,
332
+ startIndex: number = 0,
333
+ account: number = 0,
334
+ isChange: boolean = false,
335
+ ): Wallet[] {
336
+ const wallets: Wallet[] = [];
337
+
338
+ for (let i = 0; i < count; i++) {
339
+ wallets.push(this.deriveUnisat(addressType, startIndex + i, account, isChange));
340
+ }
341
+
342
+ return wallets;
343
+ }
344
+
228
345
  /**
229
346
  * Derive multiple wallets with sequential indices
230
347
  *
@@ -232,6 +349,7 @@ export class Mnemonic {
232
349
  * @param startIndex - The starting address index (default: 0)
233
350
  * @param account - The account index (default: 0)
234
351
  * @param isChange - Whether these are change addresses (default: false)
352
+ * @param bipStandard - The BIP standard to use for classical derivation (default: BIP84)
235
353
  * @returns An array of Wallet instances
236
354
  */
237
355
  public deriveMultiple(
@@ -239,11 +357,12 @@ export class Mnemonic {
239
357
  startIndex: number = 0,
240
358
  account: number = 0,
241
359
  isChange: boolean = false,
360
+ bipStandard: BIPStandard = BIPStandard.BIP84,
242
361
  ): Wallet[] {
243
362
  const wallets: Wallet[] = [];
244
363
 
245
364
  for (let i = 0; i < count; i++) {
246
- wallets.push(this.derive(startIndex + i, account, isChange));
365
+ wallets.push(this.derive(startIndex + i, account, isChange, bipStandard));
247
366
  }
248
367
 
249
368
  return wallets;
@@ -296,17 +415,23 @@ export class Mnemonic {
296
415
  }
297
416
 
298
417
  /**
299
- * Build a classical derivation path (BIP84 for Native SegWit)
418
+ * Build a classical derivation path using specified BIP standard
300
419
  *
301
420
  * @param account - The account index
302
421
  * @param index - The address index
303
422
  * @param isChange - Whether this is a change address
423
+ * @param bipStandard - The BIP standard to use (default: BIP84)
304
424
  * @returns The derivation path string
305
425
  */
306
- private buildClassicalPath(account: number, index: number, isChange: boolean): string {
426
+ private buildClassicalPath(
427
+ account: number,
428
+ index: number,
429
+ isChange: boolean,
430
+ bipStandard: BIPStandard = BIPStandard.BIP84,
431
+ ): string {
307
432
  const coinType = this.getCoinType();
308
433
  const change = isChange ? 1 : 0;
309
- return `m/84'/${coinType}'/${account}'/${change}/${index}`;
434
+ return buildBIPPath(bipStandard, coinType, account, change, index);
310
435
  }
311
436
 
312
437
  /**
package/src/opnet.ts CHANGED
@@ -33,6 +33,7 @@ export * from './keypair/Wallet.js';
33
33
  /** Mnemonic */
34
34
  export * from './mnemonic/Mnemonic.js';
35
35
  export * from './mnemonic/MnemonicStrength.js';
36
+ export * from './mnemonic/BIPStandard.js';
36
37
 
37
38
  /** Quantum (ML-DSA) */
38
39
  export {