@btc-vision/transaction 1.6.19 → 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.
- package/browser/index.js +1 -1
- package/browser/index.js.LICENSE.txt +2 -0
- package/browser/src/_version.d.ts +1 -0
- package/browser/{epoch → src/epoch}/interfaces/IChallengeSolution.d.ts +2 -0
- package/browser/{keypair → src/keypair}/Address.d.ts +7 -4
- package/browser/{keypair → src/keypair}/AddressVerificator.d.ts +3 -0
- package/browser/{keypair → src/keypair}/EcKeyPair.d.ts +3 -2
- package/browser/{keypair → src/keypair}/MessageSigner.d.ts +9 -0
- package/browser/src/keypair/Wallet.d.ts +47 -0
- package/browser/{keypair → src/keypair}/interfaces/IWallet.d.ts +2 -0
- package/browser/src/mnemonic/Mnemonic.d.ts +29 -0
- package/browser/src/mnemonic/MnemonicStrength.d.ts +7 -0
- package/browser/{opnet.d.ts → src/opnet.d.ts} +4 -0
- package/browser/src/transaction/browser/types/OPWallet.d.ts +14 -0
- package/browser/test/address.test.d.ts +1 -0
- package/browser/test/addressverificator-mldsa.test.d.ts +1 -0
- package/browser/test/derivePath.test.d.ts +1 -0
- package/browser/test/messagesigner-mldsa.test.d.ts +1 -0
- package/browser/test/messagesigner-schnorr.test.d.ts +1 -0
- package/browser/test/network-awareness.test.d.ts +1 -0
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/crypto/crypto-browser.d.ts +11 -0
- package/build/crypto/crypto-browser.js +56 -0
- package/build/epoch/ChallengeSolution.js +3 -2
- package/build/epoch/interfaces/IChallengeSolution.d.ts +2 -0
- package/build/keypair/Address.d.ts +7 -4
- package/build/keypair/Address.js +88 -37
- package/build/keypair/AddressVerificator.d.ts +3 -0
- package/build/keypair/AddressVerificator.js +49 -1
- package/build/keypair/EcKeyPair.d.ts +3 -2
- package/build/keypair/EcKeyPair.js +17 -3
- package/build/keypair/MessageSigner.d.ts +9 -0
- package/build/keypair/MessageSigner.js +23 -0
- package/build/keypair/Wallet.d.ts +20 -3
- package/build/keypair/Wallet.js +108 -9
- package/build/keypair/interfaces/IWallet.d.ts +2 -0
- package/build/mnemonic/Mnemonic.d.ts +29 -0
- package/build/mnemonic/Mnemonic.js +98 -0
- package/build/mnemonic/MnemonicStrength.d.ts +7 -0
- package/build/mnemonic/MnemonicStrength.js +8 -0
- package/build/opnet.d.ts +4 -0
- package/build/opnet.js +4 -0
- package/build/transaction/browser/types/OPWallet.d.ts +14 -0
- package/build/transaction/browser/types/OPWallet.js +6 -0
- package/gulpfile.js +2 -2
- package/package.json +25 -17
- package/src/_version.ts +1 -1
- package/src/epoch/ChallengeSolution.ts +3 -2
- package/src/epoch/interfaces/IChallengeSolution.ts +2 -0
- package/src/keypair/Address.ts +145 -43
- package/src/keypair/AddressVerificator.ts +87 -2
- package/src/keypair/EcKeyPair.ts +58 -6
- package/src/keypair/MessageSigner.ts +58 -0
- package/src/keypair/Wallet.ts +339 -57
- package/src/keypair/interfaces/IWallet.ts +13 -3
- package/src/mnemonic/Mnemonic.ts +340 -0
- package/src/mnemonic/MnemonicStrength.ts +12 -0
- package/src/network/ChainId.ts +1 -4
- package/src/opnet.ts +16 -0
- package/src/transaction/browser/types/OPWallet.ts +73 -0
- package/test/address.test.ts +1068 -0
- package/test/addressverificator-mldsa.test.ts +473 -0
- package/test/derivePath.test.ts +234 -0
- package/test/messagesigner-mldsa.test.ts +1060 -0
- package/test/messagesigner-schnorr.test.ts +1011 -0
- package/test/network-awareness.test.ts +163 -0
- package/tsconfig.json +1 -1
- package/vitest.config.ts +21 -0
- package/browser/_version.d.ts +0 -1
- package/browser/keypair/Wallet.d.ts +0 -30
- /package/browser/{abi → src/abi}/ABICoder.d.ts +0 -0
- /package/browser/{buffer → src/buffer}/BinaryReader.d.ts +0 -0
- /package/browser/{buffer → src/buffer}/BinaryWriter.d.ts +0 -0
- /package/browser/{bytecode → src/bytecode}/Compressor.d.ts +0 -0
- /package/browser/{consensus → src/consensus}/Consensus.d.ts +0 -0
- /package/browser/{consensus → src/consensus}/ConsensusConfig.d.ts +0 -0
- /package/browser/{consensus → src/consensus}/metadata/RoswellConsensus.d.ts +0 -0
- /package/browser/{crypto → src/crypto}/crypto-browser.d.ts +0 -0
- /package/browser/{crypto → src/crypto}/crypto.d.ts +0 -0
- /package/browser/{deterministic → src/deterministic}/AddressMap.d.ts +0 -0
- /package/browser/{deterministic → src/deterministic}/AddressSet.d.ts +0 -0
- /package/browser/{deterministic → src/deterministic}/DeterministicMap.d.ts +0 -0
- /package/browser/{deterministic → src/deterministic}/DeterministicSet.d.ts +0 -0
- /package/browser/{deterministic → src/deterministic}/Map.d.ts +0 -0
- /package/browser/{epoch → src/epoch}/ChallengeSolution.d.ts +0 -0
- /package/browser/{epoch → src/epoch}/validator/EpochValidator.d.ts +0 -0
- /package/browser/{event → src/event}/NetEvent.d.ts +0 -0
- /package/browser/{generators → src/generators}/AddressGenerator.d.ts +0 -0
- /package/browser/{generators → src/generators}/Features.d.ts +0 -0
- /package/browser/{generators → src/generators}/Generator.d.ts +0 -0
- /package/browser/{generators → src/generators}/builders/CalldataGenerator.d.ts +0 -0
- /package/browser/{generators → src/generators}/builders/CustomGenerator.d.ts +0 -0
- /package/browser/{generators → src/generators}/builders/DeploymentGenerator.d.ts +0 -0
- /package/browser/{generators → src/generators}/builders/LegacyCalldataGenerator.d.ts +0 -0
- /package/browser/{generators → src/generators}/builders/MultiSignGenerator.d.ts +0 -0
- /package/browser/{generators → src/generators}/builders/P2WDAGenerator.d.ts +0 -0
- /package/browser/{index.d.ts → src/index.d.ts} +0 -0
- /package/browser/{keypair → src/keypair}/Secp256k1PointDeriver.d.ts +0 -0
- /package/browser/{metadata → src/metadata}/ContractBaseMetadata.d.ts +0 -0
- /package/browser/{metadata → src/metadata}/tokens.d.ts +0 -0
- /package/browser/{network → src/network}/ChainId.d.ts +0 -0
- /package/browser/{p2wda → src/p2wda}/P2WDADetector.d.ts +0 -0
- /package/browser/{signer → src/signer}/SignerUtils.d.ts +0 -0
- /package/browser/{signer → src/signer}/TweakedSigner.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/ContractAddress.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/TransactionFactory.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/browser/BrowserSignerBase.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/browser/Web3Provider.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/browser/extensions/UnisatSigner.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/browser/extensions/XverseSigner.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/browser/types/Unisat.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/browser/types/Xverse.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/builders/CancelTransaction.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/builders/ChallengeSolutionTransaction.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/builders/CustomScriptTransaction.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/builders/DeploymentTransaction.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/builders/FundingTransaction.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/builders/InteractionTransaction.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/builders/InteractionTransactionP2WDA.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/builders/MultiSignTransaction.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/builders/SharedInteractionTransaction.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/builders/TransactionBuilder.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/enums/TransactionType.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/interfaces/ITransactionParameters.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/interfaces/Tap.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/mineable/IP2WSHAddress.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/mineable/TimelockGenerator.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/processor/PsbtTransaction.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/psbt/PSBTTypes.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/shared/P2TR_MS.d.ts +0 -0
- /package/browser/{transaction → src/transaction}/shared/TweakedTransaction.d.ts +0 -0
- /package/browser/{utils → src/utils}/BitcoinUtils.d.ts +0 -0
- /package/browser/{utils → src/utils}/BufferHelper.d.ts +0 -0
- /package/browser/{utils → src/utils}/StringToBuffer.d.ts +0 -0
- /package/browser/{utils → src/utils}/lengths.d.ts +0 -0
- /package/browser/{utils → src/utils}/types.d.ts +0 -0
- /package/browser/{utxo → src/utxo}/OPNetLimitedProvider.d.ts +0 -0
- /package/browser/{utxo → src/utxo}/interfaces/BroadcastResponse.d.ts +0 -0
- /package/browser/{utxo → src/utxo}/interfaces/IUTXO.d.ts +0 -0
- /package/browser/{verification → src/verification}/TapscriptVerificator.d.ts +0 -0
package/src/keypair/Wallet.ts
CHANGED
|
@@ -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
|
-
*
|
|
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
|
-
*
|
|
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.
|
|
194
|
+
this._segwitLegacy = this._address.p2shp2wpkh(this.network);
|
|
90
195
|
this._p2wda = this._address.p2wda(this.network);
|
|
91
196
|
|
|
92
|
-
this._tweakedKey = this._address.
|
|
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
|
|
123
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
182
|
-
|
|
183
|
-
|
|
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
|
|
193
|
-
*
|
|
194
|
-
* @param
|
|
195
|
-
* @
|
|
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
|
|
198
|
-
|
|
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
|
-
*
|
|
203
|
-
*
|
|
409
|
+
* Export the classical private key as WIF
|
|
410
|
+
*
|
|
411
|
+
* @returns The WIF-encoded private key
|
|
204
412
|
*/
|
|
205
|
-
public
|
|
206
|
-
return
|
|
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
|
}
|