@btc-vision/transaction 1.7.0 → 1.7.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/browser/index.js +1 -1
- package/browser/src/_version.d.ts +1 -1
- package/browser/src/buffer/BinaryReader.d.ts +2 -2
- package/browser/src/deterministic/AddressMap.d.ts +12 -5
- package/browser/src/deterministic/AddressSet.d.ts +2 -1
- package/browser/src/deterministic/DeterministicMap.d.ts +1 -1
- package/browser/src/keypair/Address.d.ts +4 -0
- package/browser/src/mnemonic/BIPStandard.d.ts +8 -0
- package/browser/src/mnemonic/Mnemonic.d.ts +7 -2
- package/browser/src/opnet.d.ts +1 -0
- package/browser/src/utils/lengths.d.ts +15 -16
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/buffer/BinaryReader.d.ts +2 -2
- package/build/deterministic/AddressMap.d.ts +12 -5
- package/build/deterministic/AddressMap.js +51 -33
- package/build/deterministic/AddressSet.d.ts +2 -1
- package/build/deterministic/AddressSet.js +17 -21
- package/build/deterministic/DeterministicMap.d.ts +1 -1
- package/build/deterministic/DeterministicMap.js +15 -15
- package/build/keypair/Address.d.ts +4 -0
- package/build/keypair/Address.js +46 -2
- package/build/mnemonic/BIPStandard.d.ts +8 -0
- package/build/mnemonic/BIPStandard.js +24 -0
- package/build/mnemonic/Mnemonic.d.ts +7 -2
- package/build/mnemonic/Mnemonic.js +48 -6
- package/build/opnet.d.ts +1 -0
- package/build/opnet.js +1 -0
- package/build/utils/lengths.d.ts +15 -16
- package/build/utils/lengths.js +1 -1
- package/documentation/README.md +32 -0
- package/documentation/quantum-support/01-introduction.md +88 -0
- package/documentation/quantum-support/02-mnemonic-and-wallet.md +457 -0
- package/documentation/quantum-support/03-address-generation.md +329 -0
- package/documentation/quantum-support/04-message-signing.md +623 -0
- package/documentation/quantum-support/05-address-verification.md +307 -0
- package/documentation/quantum-support/README.md +65 -0
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/buffer/BinaryReader.ts +3 -3
- package/src/buffer/BinaryWriter.ts +2 -2
- package/src/deterministic/AddressMap.ts +64 -37
- package/src/deterministic/AddressSet.ts +20 -26
- package/src/deterministic/DeterministicMap.ts +16 -13
- package/src/keypair/Address.ts +136 -0
- package/src/mnemonic/BIPStandard.ts +92 -0
- package/src/mnemonic/Mnemonic.ts +133 -8
- package/src/opnet.ts +1 -0
- package/src/utils/lengths.ts +15 -17
- package/test/derivePath.test.ts +280 -1
- package/browser/src/deterministic/Map.d.ts +0 -15
- package/build/deterministic/Map.d.ts +0 -15
- package/build/deterministic/Map.js +0 -63
- package/doc/README.md +0 -0
- package/src/deterministic/Map.ts +0 -74
- /package/{doc → documentation}/addresses/P2OP.md +0 -0
- /package/{doc → documentation}/addresses/P2WDA.md +0 -0
|
@@ -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
package/src/_version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.7.
|
|
1
|
+
export const version = '1.7.1';
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
U64_BYTE_LENGTH,
|
|
11
11
|
U8_BYTE_LENGTH,
|
|
12
12
|
} from '../utils/lengths.js';
|
|
13
|
-
import { BufferLike,
|
|
13
|
+
import { BufferLike, Selector, u16, u32, u8 } from '../utils/types.js';
|
|
14
14
|
|
|
15
15
|
export class BinaryReader {
|
|
16
16
|
private buffer: DataView;
|
|
17
|
-
private currentOffset:
|
|
17
|
+
private currentOffset: number = 0;
|
|
18
18
|
|
|
19
19
|
constructor(bytes: BufferLike) {
|
|
20
20
|
this.buffer = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
@@ -342,7 +342,7 @@ export class BinaryReader {
|
|
|
342
342
|
/**
|
|
343
343
|
* Verifies we have enough bytes in the buffer to read up to `size`.
|
|
344
344
|
*/
|
|
345
|
-
public verifyEnd(size:
|
|
345
|
+
public verifyEnd(size: number): void {
|
|
346
346
|
if (size > this.buffer.byteLength) {
|
|
347
347
|
throw new Error(
|
|
348
348
|
`Attempt to read beyond buffer length: requested up to byte offset ${size}, but buffer is only ${this.buffer.byteLength} bytes.`,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
U64_BYTE_LENGTH,
|
|
12
12
|
U8_BYTE_LENGTH,
|
|
13
13
|
} from '../utils/lengths.js';
|
|
14
|
-
import {
|
|
14
|
+
import { Selector, u16, u32, u64, u8 } from '../utils/types.js';
|
|
15
15
|
import { BinaryReader } from './BinaryReader.js';
|
|
16
16
|
|
|
17
17
|
export class BinaryWriter {
|
|
@@ -351,7 +351,7 @@ export class BinaryWriter {
|
|
|
351
351
|
|
|
352
352
|
private resize(size: u32): void {
|
|
353
353
|
const buf: Uint8Array = new Uint8Array(this.buffer.byteLength + size);
|
|
354
|
-
for (let i:
|
|
354
|
+
for (let i: number = 0; i < this.buffer.byteLength; i++) {
|
|
355
355
|
buf[i] = this.buffer.getUint8(i);
|
|
356
356
|
}
|
|
357
357
|
|
|
@@ -1,63 +1,90 @@
|
|
|
1
|
-
import { i32 } from '../utils/types.js';
|
|
2
1
|
import { Address } from '../keypair/Address.js';
|
|
3
|
-
import { Map } from './Map.js';
|
|
4
2
|
|
|
5
|
-
export class AddressMap<V>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
export class AddressMap<V> {
|
|
4
|
+
private items: Map<bigint, V>;
|
|
5
|
+
private keyOrder: Address[];
|
|
6
|
+
|
|
7
|
+
constructor(iterable?: ReadonlyArray<readonly [Address, V]> | null) {
|
|
8
|
+
this.items = new Map();
|
|
9
|
+
this.keyOrder = [];
|
|
10
|
+
|
|
11
|
+
if (iterable) {
|
|
12
|
+
for (const [key, value] of iterable) {
|
|
13
|
+
this.set(key, value);
|
|
14
|
+
}
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
get size(): number {
|
|
19
|
+
return this.keyOrder.length;
|
|
20
|
+
}
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
public set(key: Address, value: V): void {
|
|
23
|
+
const keyBigInt = key.toBigInt();
|
|
24
|
+
if (!this.items.has(keyBigInt)) {
|
|
25
|
+
this.keyOrder.push(key);
|
|
23
26
|
}
|
|
27
|
+
this.items.set(keyBigInt, value);
|
|
28
|
+
}
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
public get(key: Address): V | undefined {
|
|
31
|
+
return this.items.get(key.toBigInt());
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
public has(key: Address): boolean {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
35
|
+
return this.items.has(key.toBigInt());
|
|
36
|
+
}
|
|
34
37
|
|
|
38
|
+
public delete(key: Address): boolean {
|
|
39
|
+
const keyBigInt = key.toBigInt();
|
|
40
|
+
if (this.items.delete(keyBigInt)) {
|
|
41
|
+
this.keyOrder = this.keyOrder.filter((k) => k.toBigInt() !== keyBigInt);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
35
44
|
return false;
|
|
36
45
|
}
|
|
37
46
|
|
|
38
|
-
public
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
public clear(): void {
|
|
48
|
+
this.items.clear();
|
|
49
|
+
this.keyOrder = [];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public indexOf(address: Address): number {
|
|
53
|
+
const addressBigInt = address.toBigInt();
|
|
54
|
+
for (let i: number = 0; i < this.keyOrder.length; i++) {
|
|
55
|
+
if (this.keyOrder[i].toBigInt() === addressBigInt) {
|
|
56
|
+
return i;
|
|
57
|
+
}
|
|
42
58
|
}
|
|
43
|
-
return
|
|
59
|
+
return -1;
|
|
44
60
|
}
|
|
45
61
|
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
return false;
|
|
62
|
+
*entries(): IterableIterator<[Address, V]> {
|
|
63
|
+
for (const key of this.keyOrder) {
|
|
64
|
+
yield [key, this.items.get(key.toBigInt()) as V];
|
|
50
65
|
}
|
|
66
|
+
}
|
|
51
67
|
|
|
52
|
-
|
|
53
|
-
this.
|
|
68
|
+
*keys(): IterableIterator<Address> {
|
|
69
|
+
yield* this.keyOrder;
|
|
70
|
+
}
|
|
54
71
|
|
|
55
|
-
|
|
72
|
+
*values(): IterableIterator<V> {
|
|
73
|
+
for (const key of this.keyOrder) {
|
|
74
|
+
yield this.items.get(key.toBigInt()) as V;
|
|
75
|
+
}
|
|
56
76
|
}
|
|
57
77
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
78
|
+
forEach(
|
|
79
|
+
callback: (value: V, key: Address, map: AddressMap<V>) => void,
|
|
80
|
+
thisArg?: unknown,
|
|
81
|
+
): void {
|
|
82
|
+
for (const key of this.keyOrder) {
|
|
83
|
+
callback.call(thisArg, this.items.get(key.toBigInt()) as V, key, this);
|
|
61
84
|
}
|
|
62
85
|
}
|
|
86
|
+
|
|
87
|
+
[Symbol.iterator](): IterableIterator<[Address, V]> {
|
|
88
|
+
return this.entries();
|
|
89
|
+
}
|
|
63
90
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { Address } from '../keypair/Address.js';
|
|
2
2
|
|
|
3
3
|
export class AddressSet {
|
|
4
|
+
private items: Set<bigint>;
|
|
4
5
|
private keys: Address[];
|
|
5
6
|
|
|
6
7
|
public constructor(keys: Address[] = []) {
|
|
7
|
-
this.
|
|
8
|
+
this.items = new Set();
|
|
9
|
+
this.keys = [];
|
|
10
|
+
|
|
11
|
+
for (const key of keys) {
|
|
12
|
+
this.add(key);
|
|
13
|
+
}
|
|
8
14
|
}
|
|
9
15
|
|
|
10
16
|
public get size(): number {
|
|
@@ -12,56 +18,44 @@ export class AddressSet {
|
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
public add(address: Address): void {
|
|
15
|
-
|
|
21
|
+
const addressBigInt = address.toBigInt();
|
|
22
|
+
if (!this.items.has(addressBigInt)) {
|
|
23
|
+
this.items.add(addressBigInt);
|
|
16
24
|
this.keys.push(address);
|
|
17
25
|
}
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
public has(address: Address): boolean {
|
|
21
|
-
|
|
22
|
-
if (this.keys[i].equals(address)) {
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return false;
|
|
29
|
+
return this.items.has(address.toBigInt());
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
public remove(address: Address): void {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.keys.splice(index, 1);
|
|
33
|
+
const addressBigInt = address.toBigInt();
|
|
34
|
+
if (this.items.delete(addressBigInt)) {
|
|
35
|
+
this.keys = this.keys.filter((k) => k.toBigInt() !== addressBigInt);
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
public clone(): AddressSet {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
for (let i = 0; i < this.keys.length; i++) {
|
|
42
|
-
clone.add(this.keys[i]);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return clone;
|
|
40
|
+
return new AddressSet(this.keys);
|
|
46
41
|
}
|
|
47
42
|
|
|
48
43
|
public clear(): void {
|
|
44
|
+
this.items.clear();
|
|
49
45
|
this.keys = [];
|
|
50
46
|
}
|
|
51
47
|
|
|
52
48
|
public combine(set: AddressSet): AddressSet {
|
|
53
49
|
const clone = this.clone();
|
|
54
50
|
|
|
55
|
-
for (
|
|
56
|
-
clone.add(
|
|
51
|
+
for (const key of set.keys) {
|
|
52
|
+
clone.add(key);
|
|
57
53
|
}
|
|
58
54
|
|
|
59
55
|
return clone;
|
|
60
56
|
}
|
|
61
57
|
|
|
62
|
-
*[Symbol.iterator]() {
|
|
63
|
-
|
|
64
|
-
yield this.keys[i];
|
|
65
|
-
}
|
|
58
|
+
*[Symbol.iterator](): IterableIterator<Address> {
|
|
59
|
+
yield* this.keys;
|
|
66
60
|
}
|
|
67
61
|
}
|