@btc-vision/transaction 1.6.18 → 1.7.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.
Files changed (141) hide show
  1. package/browser/index.js +1 -1
  2. package/browser/index.js.LICENSE.txt +2 -0
  3. package/browser/src/_version.d.ts +1 -0
  4. package/browser/{epoch → src/epoch}/interfaces/IChallengeSolution.d.ts +2 -0
  5. package/browser/{keypair → src/keypair}/Address.d.ts +7 -4
  6. package/browser/{keypair → src/keypair}/AddressVerificator.d.ts +3 -0
  7. package/browser/{keypair → src/keypair}/EcKeyPair.d.ts +3 -2
  8. package/browser/{keypair → src/keypair}/MessageSigner.d.ts +9 -0
  9. package/browser/src/keypair/Wallet.d.ts +47 -0
  10. package/browser/{keypair → src/keypair}/interfaces/IWallet.d.ts +2 -0
  11. package/browser/src/mnemonic/Mnemonic.d.ts +29 -0
  12. package/browser/src/mnemonic/MnemonicStrength.d.ts +7 -0
  13. package/browser/{opnet.d.ts → src/opnet.d.ts} +4 -0
  14. package/browser/src/transaction/browser/types/OPWallet.d.ts +14 -0
  15. package/browser/test/address.test.d.ts +1 -0
  16. package/browser/test/addressverificator-mldsa.test.d.ts +1 -0
  17. package/browser/test/derivePath.test.d.ts +1 -0
  18. package/browser/test/messagesigner-mldsa.test.d.ts +1 -0
  19. package/browser/test/messagesigner-schnorr.test.d.ts +1 -0
  20. package/browser/test/network-awareness.test.d.ts +1 -0
  21. package/build/_version.d.ts +1 -1
  22. package/build/_version.js +1 -1
  23. package/build/crypto/crypto-browser.d.ts +11 -0
  24. package/build/crypto/crypto-browser.js +56 -0
  25. package/build/epoch/ChallengeSolution.js +3 -2
  26. package/build/epoch/interfaces/IChallengeSolution.d.ts +2 -0
  27. package/build/keypair/Address.d.ts +7 -4
  28. package/build/keypair/Address.js +88 -37
  29. package/build/keypair/AddressVerificator.d.ts +3 -0
  30. package/build/keypair/AddressVerificator.js +49 -1
  31. package/build/keypair/EcKeyPair.d.ts +3 -2
  32. package/build/keypair/EcKeyPair.js +17 -3
  33. package/build/keypair/MessageSigner.d.ts +9 -0
  34. package/build/keypair/MessageSigner.js +23 -0
  35. package/build/keypair/Wallet.d.ts +20 -3
  36. package/build/keypair/Wallet.js +108 -9
  37. package/build/keypair/interfaces/IWallet.d.ts +2 -0
  38. package/build/mnemonic/Mnemonic.d.ts +29 -0
  39. package/build/mnemonic/Mnemonic.js +98 -0
  40. package/build/mnemonic/MnemonicStrength.d.ts +7 -0
  41. package/build/mnemonic/MnemonicStrength.js +8 -0
  42. package/build/opnet.d.ts +4 -0
  43. package/build/opnet.js +4 -0
  44. package/build/transaction/browser/types/OPWallet.d.ts +14 -0
  45. package/build/transaction/browser/types/OPWallet.js +6 -0
  46. package/gulpfile.js +2 -2
  47. package/package.json +28 -20
  48. package/src/_version.ts +1 -1
  49. package/src/epoch/ChallengeSolution.ts +3 -2
  50. package/src/epoch/interfaces/IChallengeSolution.ts +2 -0
  51. package/src/keypair/Address.ts +145 -43
  52. package/src/keypair/AddressVerificator.ts +87 -2
  53. package/src/keypair/EcKeyPair.ts +58 -6
  54. package/src/keypair/MessageSigner.ts +58 -0
  55. package/src/keypair/Wallet.ts +339 -57
  56. package/src/keypair/interfaces/IWallet.ts +13 -3
  57. package/src/mnemonic/Mnemonic.ts +340 -0
  58. package/src/mnemonic/MnemonicStrength.ts +12 -0
  59. package/src/network/ChainId.ts +1 -4
  60. package/src/opnet.ts +16 -0
  61. package/src/transaction/browser/types/OPWallet.ts +73 -0
  62. package/test/address.test.ts +1068 -0
  63. package/test/addressverificator-mldsa.test.ts +473 -0
  64. package/test/derivePath.test.ts +234 -0
  65. package/test/messagesigner-mldsa.test.ts +1060 -0
  66. package/test/messagesigner-schnorr.test.ts +1011 -0
  67. package/test/network-awareness.test.ts +163 -0
  68. package/tsconfig.json +1 -1
  69. package/vitest.config.ts +21 -0
  70. package/browser/_version.d.ts +0 -1
  71. package/browser/keypair/Wallet.d.ts +0 -30
  72. /package/browser/{abi → src/abi}/ABICoder.d.ts +0 -0
  73. /package/browser/{buffer → src/buffer}/BinaryReader.d.ts +0 -0
  74. /package/browser/{buffer → src/buffer}/BinaryWriter.d.ts +0 -0
  75. /package/browser/{bytecode → src/bytecode}/Compressor.d.ts +0 -0
  76. /package/browser/{consensus → src/consensus}/Consensus.d.ts +0 -0
  77. /package/browser/{consensus → src/consensus}/ConsensusConfig.d.ts +0 -0
  78. /package/browser/{consensus → src/consensus}/metadata/RoswellConsensus.d.ts +0 -0
  79. /package/browser/{crypto → src/crypto}/crypto-browser.d.ts +0 -0
  80. /package/browser/{crypto → src/crypto}/crypto.d.ts +0 -0
  81. /package/browser/{deterministic → src/deterministic}/AddressMap.d.ts +0 -0
  82. /package/browser/{deterministic → src/deterministic}/AddressSet.d.ts +0 -0
  83. /package/browser/{deterministic → src/deterministic}/DeterministicMap.d.ts +0 -0
  84. /package/browser/{deterministic → src/deterministic}/DeterministicSet.d.ts +0 -0
  85. /package/browser/{deterministic → src/deterministic}/Map.d.ts +0 -0
  86. /package/browser/{epoch → src/epoch}/ChallengeSolution.d.ts +0 -0
  87. /package/browser/{epoch → src/epoch}/validator/EpochValidator.d.ts +0 -0
  88. /package/browser/{event → src/event}/NetEvent.d.ts +0 -0
  89. /package/browser/{generators → src/generators}/AddressGenerator.d.ts +0 -0
  90. /package/browser/{generators → src/generators}/Features.d.ts +0 -0
  91. /package/browser/{generators → src/generators}/Generator.d.ts +0 -0
  92. /package/browser/{generators → src/generators}/builders/CalldataGenerator.d.ts +0 -0
  93. /package/browser/{generators → src/generators}/builders/CustomGenerator.d.ts +0 -0
  94. /package/browser/{generators → src/generators}/builders/DeploymentGenerator.d.ts +0 -0
  95. /package/browser/{generators → src/generators}/builders/LegacyCalldataGenerator.d.ts +0 -0
  96. /package/browser/{generators → src/generators}/builders/MultiSignGenerator.d.ts +0 -0
  97. /package/browser/{generators → src/generators}/builders/P2WDAGenerator.d.ts +0 -0
  98. /package/browser/{index.d.ts → src/index.d.ts} +0 -0
  99. /package/browser/{keypair → src/keypair}/Secp256k1PointDeriver.d.ts +0 -0
  100. /package/browser/{metadata → src/metadata}/ContractBaseMetadata.d.ts +0 -0
  101. /package/browser/{metadata → src/metadata}/tokens.d.ts +0 -0
  102. /package/browser/{network → src/network}/ChainId.d.ts +0 -0
  103. /package/browser/{p2wda → src/p2wda}/P2WDADetector.d.ts +0 -0
  104. /package/browser/{signer → src/signer}/SignerUtils.d.ts +0 -0
  105. /package/browser/{signer → src/signer}/TweakedSigner.d.ts +0 -0
  106. /package/browser/{transaction → src/transaction}/ContractAddress.d.ts +0 -0
  107. /package/browser/{transaction → src/transaction}/TransactionFactory.d.ts +0 -0
  108. /package/browser/{transaction → src/transaction}/browser/BrowserSignerBase.d.ts +0 -0
  109. /package/browser/{transaction → src/transaction}/browser/Web3Provider.d.ts +0 -0
  110. /package/browser/{transaction → src/transaction}/browser/extensions/UnisatSigner.d.ts +0 -0
  111. /package/browser/{transaction → src/transaction}/browser/extensions/XverseSigner.d.ts +0 -0
  112. /package/browser/{transaction → src/transaction}/browser/types/Unisat.d.ts +0 -0
  113. /package/browser/{transaction → src/transaction}/browser/types/Xverse.d.ts +0 -0
  114. /package/browser/{transaction → src/transaction}/builders/CancelTransaction.d.ts +0 -0
  115. /package/browser/{transaction → src/transaction}/builders/ChallengeSolutionTransaction.d.ts +0 -0
  116. /package/browser/{transaction → src/transaction}/builders/CustomScriptTransaction.d.ts +0 -0
  117. /package/browser/{transaction → src/transaction}/builders/DeploymentTransaction.d.ts +0 -0
  118. /package/browser/{transaction → src/transaction}/builders/FundingTransaction.d.ts +0 -0
  119. /package/browser/{transaction → src/transaction}/builders/InteractionTransaction.d.ts +0 -0
  120. /package/browser/{transaction → src/transaction}/builders/InteractionTransactionP2WDA.d.ts +0 -0
  121. /package/browser/{transaction → src/transaction}/builders/MultiSignTransaction.d.ts +0 -0
  122. /package/browser/{transaction → src/transaction}/builders/SharedInteractionTransaction.d.ts +0 -0
  123. /package/browser/{transaction → src/transaction}/builders/TransactionBuilder.d.ts +0 -0
  124. /package/browser/{transaction → src/transaction}/enums/TransactionType.d.ts +0 -0
  125. /package/browser/{transaction → src/transaction}/interfaces/ITransactionParameters.d.ts +0 -0
  126. /package/browser/{transaction → src/transaction}/interfaces/Tap.d.ts +0 -0
  127. /package/browser/{transaction → src/transaction}/mineable/IP2WSHAddress.d.ts +0 -0
  128. /package/browser/{transaction → src/transaction}/mineable/TimelockGenerator.d.ts +0 -0
  129. /package/browser/{transaction → src/transaction}/processor/PsbtTransaction.d.ts +0 -0
  130. /package/browser/{transaction → src/transaction}/psbt/PSBTTypes.d.ts +0 -0
  131. /package/browser/{transaction → src/transaction}/shared/P2TR_MS.d.ts +0 -0
  132. /package/browser/{transaction → src/transaction}/shared/TweakedTransaction.d.ts +0 -0
  133. /package/browser/{utils → src/utils}/BitcoinUtils.d.ts +0 -0
  134. /package/browser/{utils → src/utils}/BufferHelper.d.ts +0 -0
  135. /package/browser/{utils → src/utils}/StringToBuffer.d.ts +0 -0
  136. /package/browser/{utils → src/utils}/lengths.d.ts +0 -0
  137. /package/browser/{utils → src/utils}/types.d.ts +0 -0
  138. /package/browser/{utxo → src/utxo}/OPNetLimitedProvider.d.ts +0 -0
  139. /package/browser/{utxo → src/utxo}/interfaces/BroadcastResponse.d.ts +0 -0
  140. /package/browser/{utxo → src/utxo}/interfaces/IUTXO.d.ts +0 -0
  141. /package/browser/{verification → src/verification}/TapscriptVerificator.d.ts +0 -0
@@ -1,72 +1,124 @@
1
1
  import { ECPairInterface } from 'ecpair';
2
2
  import { EcKeyPair } from './EcKeyPair.js';
3
- import { Network, networks, toXOnly } from '@btc-vision/bitcoin';
3
+ import { initEccLib, Network, networks, toXOnly } from '@btc-vision/bitcoin';
4
4
  import { Address } from './Address.js';
5
5
  import { BitcoinUtils } from '../utils/BitcoinUtils.js';
6
6
  import { IP2WSHAddress } from '../transaction/mineable/IP2WSHAddress.js';
7
+ import * as ecc from '@bitcoinerlab/secp256k1';
8
+ import {
9
+ getMLDSAConfig,
10
+ MLDSASecurityLevel,
11
+ QuantumBIP32Factory,
12
+ QuantumBIP32Interface,
13
+ } from '@btc-vision/bip32';
14
+ import { randomBytes } from 'crypto';
15
+
16
+ initEccLib(ecc);
7
17
 
8
18
  /**
9
- * Wallet class
19
+ * Wallet class for managing both classical and quantum-resistant keys
20
+ *
21
+ * This class represents a wallet with both ECDSA/Schnorr keys (for classical Bitcoin transactions)
22
+ * and ML-DSA keys (for quantum-resistant security). It can be created from private keys, WIF strings,
23
+ * or generated randomly.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // Create from private keys
28
+ * const wallet = new Wallet(classicalPrivateKey, mldsaPrivateKey);
29
+ *
30
+ * // Generate a new random wallet
31
+ * const newWallet = Wallet.generate();
32
+ *
33
+ * // Create from WIF
34
+ * const walletFromWif = Wallet.fromWif(wif, quantumWif);
35
+ *
36
+ * // Export keys
37
+ * const classicalWif = wallet.toWIF();
38
+ * const quantumHex = wallet.quantumPrivateKeyHex;
39
+ * ```
10
40
  */
11
41
  export class Wallet {
12
42
  /**
13
- * Keypair for the wallet
14
- * @private
43
+ * Classical ECDSA/Schnorr keypair for the wallet
15
44
  */
16
45
  private readonly _keypair: ECPairInterface;
17
46
 
47
+ /**
48
+ * Quantum ML-DSA keypair for the wallet
49
+ */
50
+ private readonly _mldsaKeypair: QuantumBIP32Interface;
51
+
52
+ /**
53
+ * The ML-DSA security level used
54
+ */
55
+ private readonly _securityLevel: MLDSASecurityLevel;
56
+
57
+ /**
58
+ * Chain code for BIP32 derivation (if applicable)
59
+ */
60
+ private readonly _chainCode: Buffer;
61
+
18
62
  /**
19
63
  * P2WPKH address for the wallet
20
- * @private
21
64
  */
22
65
  private readonly _p2wpkh: string;
23
66
 
24
67
  /**
25
- * P2TR address for the wallet
26
- * @private
68
+ * P2TR (Taproot) address for the wallet
27
69
  */
28
70
  private readonly _p2tr: string;
29
71
 
30
72
  /**
31
- * P2WDA Pay-to-Witness-Data-Authentication
32
- * @private
73
+ * P2WDA (Pay-to-Witness-Data-Authentication) address
33
74
  */
34
75
  private readonly _p2wda: IP2WSHAddress;
35
76
 
36
77
  /**
37
- * Legacy address for the wallet
38
- * @private
78
+ * Legacy P2PKH address for the wallet
39
79
  */
40
80
  private readonly _legacy: string;
41
81
 
42
82
  /**
43
- * Legacy address for the wallet
44
- * @private
83
+ * Legacy SegWit (P2SH-P2WPKH) address for the wallet
45
84
  */
46
85
  private readonly _segwitLegacy: string;
47
86
 
48
87
  /**
49
- * Buffer public key
50
- * @private
88
+ * Classical public key buffer
51
89
  */
52
90
  private readonly _bufferPubKey: Buffer;
53
91
 
54
92
  /**
55
- * Tweaked key
56
- * @private
93
+ * Tweaked key for Taproot
57
94
  */
58
95
  private readonly _tweakedKey: Buffer;
59
96
 
60
97
  /**
61
98
  * Address corresponding to the wallet
62
- * @private
63
99
  */
64
100
  private readonly _address: Address;
65
101
 
102
+ /**
103
+ * Create a new Wallet instance
104
+ *
105
+ * @param privateKeyOrWif - Classical private key (hex or WIF format)
106
+ * @param mldsaPrivateKeyOrBase58 - ML-DSA private key (hex format) or full base58 extended key
107
+ * @param network - The Bitcoin network to use (default: bitcoin mainnet)
108
+ * @param securityLevel - The ML-DSA security level (default: LEVEL2/44)
109
+ * @param chainCode - Optional chain code for BIP32 derivation (32 bytes)
110
+ * @throws {Error} If the private keys are invalid
111
+ */
66
112
  constructor(
67
113
  privateKeyOrWif: string,
114
+ mldsaPrivateKeyOrBase58: string,
68
115
  public readonly network: Network = networks.bitcoin,
116
+ securityLevel: MLDSASecurityLevel = MLDSASecurityLevel.LEVEL2,
117
+ chainCode?: Buffer,
69
118
  ) {
119
+ this._securityLevel = securityLevel;
120
+
121
+ // Parse classical private key
70
122
  const parsedPrivateKey = privateKeyOrWif.startsWith('0x')
71
123
  ? privateKeyOrWif.replace('0x', '')
72
124
  : privateKeyOrWif;
@@ -80,129 +132,359 @@ export class Wallet {
80
132
  this._keypair = EcKeyPair.fromWIF(parsedPrivateKey, this.network);
81
133
  }
82
134
 
135
+ // Parse ML-DSA private key
136
+ const parsedMLDSAKey = mldsaPrivateKeyOrBase58.startsWith('0x')
137
+ ? mldsaPrivateKeyOrBase58.replace('0x', '')
138
+ : mldsaPrivateKeyOrBase58;
139
+
140
+ // Check if it's a base58 extended key
141
+ if (BitcoinUtils.isValidHex(parsedMLDSAKey)) {
142
+ // It's a raw hex private key (possibly with public key concatenated)
143
+ const mldsaBuffer = Buffer.from(parsedMLDSAKey, 'hex');
144
+
145
+ // Get expected lengths for this security level and network
146
+ const config = getMLDSAConfig(securityLevel, this.network);
147
+ const privateKeySize = config.privateKeySize;
148
+ const publicKeySize = config.publicKeySize;
149
+ const combinedSize = privateKeySize + publicKeySize;
150
+
151
+ let mldsaPrivateKeyBuffer: Buffer;
152
+
153
+ // Check if it's just the private key, or private+public combined
154
+ if (mldsaBuffer.length === privateKeySize) {
155
+ // Just the private key
156
+ mldsaPrivateKeyBuffer = mldsaBuffer;
157
+ } else if (mldsaBuffer.length === combinedSize) {
158
+ // Combined privateKey || publicKey format (from Mnemonic.derive)
159
+ // Extract just the private key portion
160
+ mldsaPrivateKeyBuffer = mldsaBuffer.subarray(0, privateKeySize);
161
+ } else {
162
+ throw new Error(
163
+ `Invalid ML-DSA key length for security level ${securityLevel}. Expected ${privateKeySize} bytes (private only) or ${combinedSize} bytes (private+public), got ${mldsaBuffer.length} bytes.`,
164
+ );
165
+ }
166
+
167
+ // Use provided chain code or generate a random one
168
+ if (chainCode && chainCode.length !== 32) {
169
+ throw new Error('Chain code must be 32 bytes');
170
+ }
171
+ this._chainCode = chainCode || randomBytes(32);
172
+
173
+ // Create QuantumBIP32Interface from private key and chain code
174
+ // Pass network to ensure network-specific derivation
175
+ this._mldsaKeypair = QuantumBIP32Factory.fromPrivateKey(
176
+ mldsaPrivateKeyBuffer,
177
+ this._chainCode,
178
+ this.network,
179
+ securityLevel,
180
+ );
181
+ } else {
182
+ this._mldsaKeypair = QuantumBIP32Factory.fromBase58(parsedMLDSAKey);
183
+ this._chainCode = Buffer.from(this._mldsaKeypair.chainCode);
184
+ this._securityLevel = this._mldsaKeypair.securityLevel;
185
+ }
186
+
187
+ // Set up addresses
83
188
  this._bufferPubKey = this._keypair.publicKey;
84
- this._address = new Address(this._keypair.publicKey);
189
+ this._address = new Address(this._mldsaKeypair.publicKey, this._keypair.publicKey);
85
190
 
86
191
  this._p2tr = this._address.p2tr(this.network);
87
192
  this._p2wpkh = this._address.p2wpkh(this.network);
88
193
  this._legacy = this._address.p2pkh(this.network);
89
- this._segwitLegacy = this._address.p2wpkh(this.network);
194
+ this._segwitLegacy = this._address.p2shp2wpkh(this.network);
90
195
  this._p2wda = this._address.p2wda(this.network);
91
196
 
92
- this._tweakedKey = this._address.toBuffer();
197
+ this._tweakedKey = this._address.tweakedPublicKeyToBuffer();
93
198
  }
94
199
 
95
200
  /**
96
201
  * Get the address for the wallet
97
- * @returns {Address}
98
202
  */
99
203
  public get address(): Address {
100
204
  return this._address;
101
205
  }
102
206
 
103
207
  /**
104
- * Get the tweaked key
105
- * @returns {Buffer}
208
+ * Get the tweaked public key for Taproot
106
209
  */
107
210
  public get tweakedPubKeyKey(): Buffer {
108
211
  return this._tweakedKey;
109
212
  }
110
213
 
111
214
  /**
112
- * Get the keypair for the wallet
113
- * @returns {ECPairInterface}
215
+ * Get the classical keypair for the wallet
114
216
  */
115
217
  public get keypair(): ECPairInterface {
116
218
  if (!this._keypair) throw new Error('Keypair not set');
117
-
118
219
  return this._keypair;
119
220
  }
120
221
 
121
222
  /**
122
- * Get the P2WPKH address for the wallet
123
- * @returns {string}
223
+ * Get the quantum ML-DSA keypair
224
+ */
225
+ public get mldsaKeypair(): QuantumBIP32Interface {
226
+ return this._mldsaKeypair;
227
+ }
228
+
229
+ /**
230
+ * Get the ML-DSA security level
231
+ */
232
+ public get securityLevel(): MLDSASecurityLevel {
233
+ return this._securityLevel;
234
+ }
235
+
236
+ /**
237
+ * Get the chain code for BIP32 derivation
238
+ */
239
+ public get chainCode(): Buffer {
240
+ return this._chainCode;
241
+ }
242
+
243
+ /**
244
+ * Get the P2WPKH (Native SegWit) address
124
245
  */
125
246
  public get p2wpkh(): string {
126
247
  return this._p2wpkh;
127
248
  }
128
249
 
129
250
  /**
130
- * Get the P2TR address for the wallet
131
- * @returns {string}
251
+ * Get the P2TR (Taproot) address
132
252
  */
133
253
  public get p2tr(): string {
134
254
  return this._p2tr;
135
255
  }
136
256
 
137
257
  /**
138
- * Get the P2WDA address for the wallet
139
- * @returns {string}
258
+ * Get the P2WDA address
140
259
  */
141
260
  public get p2wda(): IP2WSHAddress {
142
261
  return this._p2wda;
143
262
  }
144
263
 
145
264
  /**
146
- * Get the legacy address for the wallet
147
- * @returns {string}
265
+ * Get the legacy P2PKH address
148
266
  */
149
267
  public get legacy(): string {
150
268
  return this._legacy;
151
269
  }
152
270
 
153
271
  /**
154
- * Get the addresses for the wallet
155
- * @returns {Address[]}
272
+ * Get all addresses for the wallet
156
273
  */
157
274
  public get addresses(): string[] {
158
275
  return [this.p2wpkh, this.p2tr, this.legacy, this.segwitLegacy];
159
276
  }
160
277
 
161
278
  /**
162
- * Get the segwit legacy address for the wallet
163
- * @returns {string}
279
+ * Get the legacy SegWit (P2SH-P2WPKH) address
164
280
  */
165
281
  public get segwitLegacy(): string {
166
282
  return this._segwitLegacy;
167
283
  }
168
284
 
169
285
  /**
170
- * Get the public key for the wallet
171
- * @protected
172
- * @returns {Buffer}
286
+ * Get the classical public key
173
287
  */
174
288
  public get publicKey(): Buffer {
175
289
  if (!this._bufferPubKey) throw new Error('Public key not set');
176
-
177
290
  return this._bufferPubKey;
178
291
  }
179
292
 
180
293
  /**
181
- * Get the x-only public key for the wallet
182
- * @public
183
- * @returns {Buffer}
294
+ * Get the quantum ML-DSA public key
295
+ */
296
+ public get quantumPublicKey(): Buffer {
297
+ return Buffer.from(this._mldsaKeypair.publicKey);
298
+ }
299
+
300
+ /**
301
+ * Get the quantum ML-DSA private key
302
+ */
303
+ public get quantumPrivateKey(): Buffer {
304
+ if (!this._mldsaKeypair.privateKey) {
305
+ throw new Error('Quantum private key not set');
306
+ }
307
+
308
+ return Buffer.from(this._mldsaKeypair.privateKey);
309
+ }
310
+
311
+ /**
312
+ * Get the quantum ML-DSA public key as hex string
313
+ */
314
+ public get quantumPublicKeyHex(): string {
315
+ return Buffer.from(this._mldsaKeypair.publicKey).toString('hex');
316
+ }
317
+
318
+ /**
319
+ * Get the quantum ML-DSA private key as hex string
320
+ */
321
+ public get quantumPrivateKeyHex(): string {
322
+ if (!this._mldsaKeypair.privateKey) {
323
+ throw new Error('Quantum private key not set');
324
+ }
325
+
326
+ return Buffer.from(this._mldsaKeypair.privateKey).toString('hex');
327
+ }
328
+
329
+ /**
330
+ * Get the x-only public key for Taproot
184
331
  */
185
332
  public get xOnly(): Buffer {
186
333
  if (!this.keypair) throw new Error('Keypair not set');
187
-
188
334
  return toXOnly(this._bufferPubKey);
189
335
  }
190
336
 
191
337
  /**
192
- * Create a wallet from a WIF
193
- * @param {string} wif The WIF
194
- * @param {Network} network The network
195
- * @returns {Wallet} The wallet
338
+ * Create a wallet from WIF strings
339
+ *
340
+ * @param wif - The classical WIF private key
341
+ * @param quantumPrivateKeyHex - The quantum ML-DSA private key (hex)
342
+ * @param network - The network (default: bitcoin mainnet)
343
+ * @param securityLevel - The ML-DSA security level (default: LEVEL2/44)
344
+ * @param chainCode - Optional chain code for BIP32 derivation
345
+ * @returns A Wallet instance
346
+ */
347
+ public static fromWif(
348
+ wif: string,
349
+ quantumPrivateKeyHex: string,
350
+ network: Network = networks.bitcoin,
351
+ securityLevel: MLDSASecurityLevel = MLDSASecurityLevel.LEVEL2,
352
+ chainCode?: Buffer,
353
+ ): Wallet {
354
+ return new Wallet(wif, quantumPrivateKeyHex, network, securityLevel, chainCode);
355
+ }
356
+
357
+ /**
358
+ * Generate a new random wallet with both classical and quantum keys
359
+ *
360
+ * @param network - The network (default: bitcoin mainnet)
361
+ * @param securityLevel - The ML-DSA security level (default: LEVEL2/44)
362
+ * @returns A new Wallet instance with randomly generated keys
363
+ */
364
+ public static generate(
365
+ network: Network = networks.bitcoin,
366
+ securityLevel: MLDSASecurityLevel = MLDSASecurityLevel.LEVEL2,
367
+ ): Wallet {
368
+ const walletData = EcKeyPair.generateWallet(network, securityLevel);
369
+
370
+ if (!walletData.quantumPrivateKey) {
371
+ throw new Error('Failed to generate quantum keys');
372
+ }
373
+
374
+ return new Wallet(
375
+ walletData.privateKey,
376
+ walletData.quantumPrivateKey,
377
+ network,
378
+ securityLevel,
379
+ );
380
+ }
381
+
382
+ /**
383
+ * Create a wallet from private key hex strings
384
+ *
385
+ * @param privateKeyHexOrWif - The classical private key
386
+ * @param mldsaPrivateKeyOrBase58 - The quantum ML-DSA private key
387
+ * @param network - The network (default: bitcoin mainnet)
388
+ * @param securityLevel - The ML-DSA security level (default: LEVEL2/44)
389
+ * @param chainCode - Optional chain code for BIP32 derivation
390
+ * @returns A Wallet instance
196
391
  */
197
- public static fromWif(wif: string, network: Network = networks.bitcoin): Wallet {
198
- return new Wallet(wif, network);
392
+ public static fromPrivateKeys(
393
+ privateKeyHexOrWif: string,
394
+ mldsaPrivateKeyOrBase58: string,
395
+ network: Network = networks.bitcoin,
396
+ securityLevel: MLDSASecurityLevel = MLDSASecurityLevel.LEVEL2,
397
+ chainCode?: Buffer,
398
+ ): Wallet {
399
+ return new Wallet(
400
+ privateKeyHexOrWif,
401
+ mldsaPrivateKeyOrBase58,
402
+ network,
403
+ securityLevel,
404
+ chainCode,
405
+ );
199
406
  }
200
407
 
201
408
  /**
202
- * Create a new fresh wallet
203
- * @param {Network} network The network
409
+ * Export the classical private key as WIF
410
+ *
411
+ * @returns The WIF-encoded private key
204
412
  */
205
- public static new(network: Network = networks.bitcoin): Wallet {
206
- return new Wallet(EcKeyPair.generateWallet(network).privateKey, network);
413
+ public toWIF(): string {
414
+ return this._keypair.toWIF();
415
+ }
416
+
417
+ /**
418
+ * Export the classical private key as hex
419
+ *
420
+ * @returns The hex-encoded private key
421
+ */
422
+ public toPrivateKeyHex(): string {
423
+ if (!this._keypair.privateKey) {
424
+ throw new Error('Private key not available');
425
+ }
426
+ return this._keypair.privateKey.toString('hex');
427
+ }
428
+
429
+ /**
430
+ * Export the classical public key as hex
431
+ *
432
+ * @returns The hex-encoded public key
433
+ */
434
+ public toPublicKeyHex(): string {
435
+ return this._bufferPubKey.toString('hex');
436
+ }
437
+
438
+ /**
439
+ * Export quantum keypair as base58 extended key
440
+ *
441
+ * @returns The base58-encoded extended quantum key
442
+ */
443
+ public toQuantumBase58(): string {
444
+ return this._mldsaKeypair.toBase58();
445
+ }
446
+
447
+ /**
448
+ * Derive a child wallet using BIP32 path
449
+ *
450
+ * @param path - BIP32 derivation path (e.g., "m/0'/0/0")
451
+ * @returns A new Wallet instance derived from this wallet
452
+ * @throws {Error} If the private key is not available for derivation
453
+ */
454
+ public derivePath(path: string): Wallet {
455
+ // Derive quantum key
456
+ const derivedQuantum = this._mldsaKeypair.derivePath(path);
457
+
458
+ // Derive classical key using BIP32
459
+ if (!this._keypair.privateKey) {
460
+ throw new Error('Cannot derive from a watch-only wallet (no private key available)');
461
+ }
462
+
463
+ // Create BIP32 node from current private key and chain code
464
+ const bip32Root = EcKeyPair.BIP32.fromPrivateKey(
465
+ this._keypair.privateKey,
466
+ this._chainCode,
467
+ this.network,
468
+ );
469
+
470
+ // Derive the child key using the provided path
471
+ const derivedClassical = bip32Root.derivePath(path);
472
+ if (!derivedClassical.privateKey) {
473
+ throw new Error('Failed to derive classical private key');
474
+ }
475
+
476
+ if (!derivedClassical.chainCode) {
477
+ throw new Error('Failed to derive classical chain code');
478
+ }
479
+
480
+ // Create new wallet from derived keys
481
+ // Pass the derived chain code so the child wallet can derive further children
482
+ return new Wallet(
483
+ Buffer.from(derivedClassical.privateKey).toString('hex'),
484
+ derivedQuantum.toBase58(),
485
+ this.network,
486
+ this._securityLevel,
487
+ Buffer.from(derivedClassical.chainCode),
488
+ );
207
489
  }
208
490
  }
@@ -3,17 +3,27 @@
3
3
  */
4
4
  export interface IWallet {
5
5
  /**
6
- * The address of the wallet
6
+ * The classical Bitcoin address of the wallet (P2WPKH)
7
7
  */
8
8
  readonly address: string;
9
9
 
10
10
  /**
11
- * The private key of the wallet
11
+ * The classical private key of the wallet (WIF format or hex)
12
12
  */
13
13
  readonly privateKey: string;
14
14
 
15
15
  /**
16
- * The public key of the wallet
16
+ * The classical public key of the wallet (hex)
17
17
  */
18
18
  readonly publicKey: string;
19
+
20
+ /**
21
+ * The quantum ML-DSA private key (hex)
22
+ */
23
+ readonly quantumPrivateKey: string;
24
+
25
+ /**
26
+ * The quantum ML-DSA public key (hex)
27
+ */
28
+ readonly quantumPublicKey: string;
19
29
  }