@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.
Files changed (57) hide show
  1. package/browser/index.js +1 -1
  2. package/browser/src/_version.d.ts +1 -1
  3. package/browser/src/buffer/BinaryReader.d.ts +2 -2
  4. package/browser/src/deterministic/AddressMap.d.ts +12 -5
  5. package/browser/src/deterministic/AddressSet.d.ts +2 -1
  6. package/browser/src/deterministic/DeterministicMap.d.ts +1 -1
  7. package/browser/src/keypair/Address.d.ts +4 -0
  8. package/browser/src/mnemonic/BIPStandard.d.ts +8 -0
  9. package/browser/src/mnemonic/Mnemonic.d.ts +7 -2
  10. package/browser/src/opnet.d.ts +1 -0
  11. package/browser/src/utils/lengths.d.ts +15 -16
  12. package/build/_version.d.ts +1 -1
  13. package/build/_version.js +1 -1
  14. package/build/buffer/BinaryReader.d.ts +2 -2
  15. package/build/deterministic/AddressMap.d.ts +12 -5
  16. package/build/deterministic/AddressMap.js +51 -33
  17. package/build/deterministic/AddressSet.d.ts +2 -1
  18. package/build/deterministic/AddressSet.js +17 -21
  19. package/build/deterministic/DeterministicMap.d.ts +1 -1
  20. package/build/deterministic/DeterministicMap.js +15 -15
  21. package/build/keypair/Address.d.ts +4 -0
  22. package/build/keypair/Address.js +46 -2
  23. package/build/mnemonic/BIPStandard.d.ts +8 -0
  24. package/build/mnemonic/BIPStandard.js +24 -0
  25. package/build/mnemonic/Mnemonic.d.ts +7 -2
  26. package/build/mnemonic/Mnemonic.js +48 -6
  27. package/build/opnet.d.ts +1 -0
  28. package/build/opnet.js +1 -0
  29. package/build/utils/lengths.d.ts +15 -16
  30. package/build/utils/lengths.js +1 -1
  31. package/documentation/README.md +32 -0
  32. package/documentation/quantum-support/01-introduction.md +88 -0
  33. package/documentation/quantum-support/02-mnemonic-and-wallet.md +457 -0
  34. package/documentation/quantum-support/03-address-generation.md +329 -0
  35. package/documentation/quantum-support/04-message-signing.md +623 -0
  36. package/documentation/quantum-support/05-address-verification.md +307 -0
  37. package/documentation/quantum-support/README.md +65 -0
  38. package/package.json +1 -1
  39. package/src/_version.ts +1 -1
  40. package/src/buffer/BinaryReader.ts +3 -3
  41. package/src/buffer/BinaryWriter.ts +2 -2
  42. package/src/deterministic/AddressMap.ts +64 -37
  43. package/src/deterministic/AddressSet.ts +20 -26
  44. package/src/deterministic/DeterministicMap.ts +16 -13
  45. package/src/keypair/Address.ts +136 -0
  46. package/src/mnemonic/BIPStandard.ts +92 -0
  47. package/src/mnemonic/Mnemonic.ts +133 -8
  48. package/src/opnet.ts +1 -0
  49. package/src/utils/lengths.ts +15 -17
  50. package/test/derivePath.test.ts +280 -1
  51. package/browser/src/deterministic/Map.d.ts +0 -15
  52. package/build/deterministic/Map.d.ts +0 -15
  53. package/build/deterministic/Map.js +0 -63
  54. package/doc/README.md +0 -0
  55. package/src/deterministic/Map.ts +0 -74
  56. /package/{doc → documentation}/addresses/P2OP.md +0 -0
  57. /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
@@ -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.2",
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';
@@ -10,11 +10,11 @@ import {
10
10
  U64_BYTE_LENGTH,
11
11
  U8_BYTE_LENGTH,
12
12
  } from '../utils/lengths.js';
13
- import { BufferLike, i32, Selector, u16, u32, u8 } from '../utils/types.js';
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: i32 = 0;
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: i32): void {
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 { i32, Selector, u16, u32, u64, u8 } from '../utils/types.js';
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: i32 = 0; i < this.buffer.byteLength; 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> extends Map<Address, V> {
6
- public set(key: Address, value: V): void {
7
- const index: i32 = this.indexOf(key);
8
- if (index == -1) {
9
- this._keys.push(key);
10
- this._values.push(value);
11
- } else {
12
- this._values[index] = value;
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
- public indexOf(address: Address): i32 {
17
- for (let i: i32 = 0; i < this._keys.length; i++) {
18
- const key = this._keys[i];
18
+ get size(): number {
19
+ return this.keyOrder.length;
20
+ }
19
21
 
20
- if (address.equals(key)) {
21
- return i;
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
- return -1;
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
- for (let i: i32 = 0; i < this._keys.length; i++) {
30
- if (key.equals(this._keys[i])) {
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 get(key: Address): V | undefined {
39
- const index: i32 = this.indexOf(key);
40
- if (index == -1) {
41
- return;
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 this._values[index];
59
+ return -1;
44
60
  }
45
61
 
46
- public delete(key: Address): boolean {
47
- const index: i32 = this.indexOf(key);
48
- if (index == -1) {
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
- this._keys.splice(index, 1);
53
- this._values.splice(index, 1);
68
+ *keys(): IterableIterator<Address> {
69
+ yield* this.keyOrder;
70
+ }
54
71
 
55
- return true;
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
- *[Symbol.iterator](): IterableIterator<[Address, V]> {
59
- for (const key of this._keys) {
60
- yield [key, this.get(key) as V];
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.keys = keys;
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
- if (!this.has(address)) {
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
- for (let i = 0; i < this.keys.length; i++) {
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 index = this.keys.findIndex((key) => key.equals(address));
32
-
33
- if (index !== -1) {
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
- const clone = new AddressSet();
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 (let i = 0; i < set.keys.length; i++) {
56
- clone.add(set.keys[i]);
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
- for (let i = 0; i < this.keys.length; i++) {
64
- yield this.keys[i];
65
- }
58
+ *[Symbol.iterator](): IterableIterator<Address> {
59
+ yield* this.keys;
66
60
  }
67
61
  }