@cheny56/node-client 1.0.7 → 1.0.8
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/package.json +2 -2
- package/src/contract.js +9 -3
- package/src/transaction.js +82 -38
- package/src/wallet.js +121 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cheny56/node-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Client library for Quorum blockchain with Post-Quantum Cryptography (PQC) and Zero-Knowledge Proof (ZK) support",
|
|
5
5
|
"main": "./index.cjs",
|
|
6
6
|
"module": "./src/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"license": "LGPL-3.0",
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"ethers": "^5.7.2",
|
|
45
|
-
"
|
|
45
|
+
"dilithium-crystals": "^1.0.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {},
|
|
48
48
|
"devDependencies": {},
|
package/src/contract.js
CHANGED
|
@@ -160,6 +160,10 @@ export class ERC20Token extends Contract {
|
|
|
160
160
|
*/
|
|
161
161
|
async transferPQC(wallet, provider, to, amount, txOptions = {}) {
|
|
162
162
|
const data = this.encodeFunctionData('transfer', [to, amount]);
|
|
163
|
+
// Ensure wallet has address
|
|
164
|
+
if (!wallet.address) {
|
|
165
|
+
await wallet._ensureKeyPair();
|
|
166
|
+
}
|
|
163
167
|
const nonce = await provider.getTransactionCount(wallet.address, 'pending');
|
|
164
168
|
|
|
165
169
|
const tx = new PQCLegacyTransaction({
|
|
@@ -172,7 +176,7 @@ export class ERC20Token extends Contract {
|
|
|
172
176
|
data: data,
|
|
173
177
|
});
|
|
174
178
|
|
|
175
|
-
tx.sign(wallet);
|
|
179
|
+
await tx.sign(wallet);
|
|
176
180
|
const serialized = tx.getHex();
|
|
177
181
|
return await provider.sendRawTransaction(serialized);
|
|
178
182
|
}
|
|
@@ -188,7 +192,9 @@ export class ERC20Token extends Contract {
|
|
|
188
192
|
*/
|
|
189
193
|
async transferHybrid(wallet, provider, to, amount, txOptions = {}) {
|
|
190
194
|
const data = this.encodeFunctionData('transfer', [to, amount]);
|
|
191
|
-
|
|
195
|
+
// Ensure wallet has address
|
|
196
|
+
const address = await wallet.getAddress();
|
|
197
|
+
const nonce = await provider.getTransactionCount(address, 'pending');
|
|
192
198
|
|
|
193
199
|
const tx = new HybridLegacyTransaction({
|
|
194
200
|
chainId: txOptions.chainId || 1337,
|
|
@@ -200,7 +206,7 @@ export class ERC20Token extends Contract {
|
|
|
200
206
|
data: data,
|
|
201
207
|
});
|
|
202
208
|
|
|
203
|
-
tx.sign(wallet.ecdsaWallet, wallet.pqcWallet);
|
|
209
|
+
await tx.sign(wallet.ecdsaWallet, wallet.pqcWallet);
|
|
204
210
|
const serialized = tx.getHex();
|
|
205
211
|
return await provider.sendRawTransaction(serialized);
|
|
206
212
|
}
|
package/src/transaction.js
CHANGED
|
@@ -8,19 +8,62 @@ import { createRequire } from 'module';
|
|
|
8
8
|
import { TX_TYPE, PQC_TYPE, DEFAULT_CHAIN_ID } from './constants.js';
|
|
9
9
|
import { encodeUint64, encodeBigInt, encodeSignature } from './utils/rlp.js';
|
|
10
10
|
|
|
11
|
-
//
|
|
12
|
-
//
|
|
11
|
+
// Import dilithium-crystals package
|
|
12
|
+
// Use createRequire to handle both ES modules and CommonJS
|
|
13
13
|
const require = createRequire(import.meta.url);
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
// Lazy load dilithium-crystals to avoid top-level await issues
|
|
16
|
+
let dilithiumCache = null;
|
|
17
|
+
|
|
18
|
+
async function getDilithium() {
|
|
19
|
+
if (dilithiumCache) {
|
|
20
|
+
return dilithiumCache;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Try ES module import first
|
|
25
|
+
const dilithiumModule = await import('dilithium-crystals');
|
|
26
|
+
dilithiumCache = dilithiumModule.default || dilithiumModule;
|
|
27
|
+
} catch (e) {
|
|
28
|
+
// Fallback to CommonJS require
|
|
29
|
+
try {
|
|
30
|
+
dilithiumCache = require('dilithium-crystals');
|
|
31
|
+
dilithiumCache = dilithiumCache.default || dilithiumCache;
|
|
32
|
+
} catch (e2) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Failed to import dilithium-crystals: ${e.message}\n` +
|
|
35
|
+
`Please ensure dilithium-crystals is installed: npm install dilithium-crystals`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return dilithiumCache;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Helper function to sign with dilithium
|
|
44
|
+
async function signWithDilithium(secretKey, hash) {
|
|
45
|
+
const dilithium = await getDilithium();
|
|
46
|
+
if (dilithium.sign) {
|
|
47
|
+
return dilithium.sign(secretKey, hash);
|
|
48
|
+
} else if (dilithium.signWithContext) {
|
|
49
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
50
|
+
return dilithium.signWithContext(secretKey, hash, ctx);
|
|
51
|
+
} else {
|
|
52
|
+
throw new Error('dilithium-crystals does not expose sign method');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Helper function to verify with dilithium
|
|
57
|
+
async function verifyWithDilithium(publicKey, hash, signature) {
|
|
58
|
+
const dilithium = await getDilithium();
|
|
59
|
+
if (dilithium.verify) {
|
|
60
|
+
return dilithium.verify(publicKey, hash, signature);
|
|
61
|
+
} else if (dilithium.verifyWithContext) {
|
|
62
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
63
|
+
return dilithium.verifyWithContext(publicKey, hash, signature, ctx);
|
|
64
|
+
} else {
|
|
65
|
+
throw new Error('dilithium-crystals does not expose verify method');
|
|
66
|
+
}
|
|
24
67
|
}
|
|
25
68
|
|
|
26
69
|
/**
|
|
@@ -121,24 +164,22 @@ export class PQCLegacyTransaction extends BaseTransaction {
|
|
|
121
164
|
/**
|
|
122
165
|
* Sign with PQC wallet
|
|
123
166
|
* @param {PQCWallet} wallet - PQC wallet
|
|
124
|
-
* @returns {PQCLegacyTransaction} This transaction
|
|
167
|
+
* @returns {Promise<PQCLegacyTransaction>} This transaction
|
|
125
168
|
*/
|
|
126
|
-
sign(wallet) {
|
|
169
|
+
async sign(wallet) {
|
|
127
170
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
128
|
-
this.pqcPubKey = wallet.publicKey;
|
|
129
|
-
|
|
130
|
-
this.pqcSig = ml_dsa65.sign(wallet.secretKey, hash, ctx);
|
|
171
|
+
this.pqcPubKey = wallet.publicKey || (await wallet._ensureKeyPair(), wallet.publicKey);
|
|
172
|
+
this.pqcSig = await signWithDilithium(wallet.secretKey, hash);
|
|
131
173
|
this.v = Number(this.chainId) * 2 + 35;
|
|
132
174
|
this.r = '0x0';
|
|
133
175
|
this.s = '0x0';
|
|
134
176
|
return this;
|
|
135
177
|
}
|
|
136
178
|
|
|
137
|
-
verify() {
|
|
179
|
+
async verify() {
|
|
138
180
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
139
181
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
140
|
-
|
|
141
|
-
return ml_dsa65.verify(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
182
|
+
return await verifyWithDilithium(this.pqcPubKey, hash, this.pqcSig);
|
|
142
183
|
}
|
|
143
184
|
|
|
144
185
|
serialize() {
|
|
@@ -224,9 +265,9 @@ export class HybridLegacyTransaction extends BaseTransaction {
|
|
|
224
265
|
* Sign with both ECDSA and PQC wallets
|
|
225
266
|
* @param {ECDSAWallet} ecdsaWallet - ECDSA wallet
|
|
226
267
|
* @param {PQCWallet} pqcWallet - PQC wallet
|
|
227
|
-
* @returns {HybridLegacyTransaction} This transaction
|
|
268
|
+
* @returns {Promise<HybridLegacyTransaction>} This transaction
|
|
228
269
|
*/
|
|
229
|
-
sign(ecdsaWallet, pqcWallet) {
|
|
270
|
+
async sign(ecdsaWallet, pqcWallet) {
|
|
230
271
|
const hash = this.getSigningHash();
|
|
231
272
|
const hashBytes = ethers.getBytes(hash);
|
|
232
273
|
|
|
@@ -238,18 +279,19 @@ export class HybridLegacyTransaction extends BaseTransaction {
|
|
|
238
279
|
this.s = ecdsaSig.s;
|
|
239
280
|
|
|
240
281
|
// PQC signature
|
|
241
|
-
|
|
282
|
+
if (!pqcWallet.publicKey) {
|
|
283
|
+
await pqcWallet._ensureKeyPair();
|
|
284
|
+
}
|
|
242
285
|
this.pqcPubKey = pqcWallet.publicKey;
|
|
243
|
-
this.pqcSig =
|
|
286
|
+
this.pqcSig = await signWithDilithium(pqcWallet.secretKey, hashBytes);
|
|
244
287
|
|
|
245
288
|
return this;
|
|
246
289
|
}
|
|
247
290
|
|
|
248
|
-
verify() {
|
|
291
|
+
async verify() {
|
|
249
292
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
250
293
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
251
|
-
|
|
252
|
-
return ml_dsa65.verify(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
294
|
+
return await verifyWithDilithium(this.pqcPubKey, hash, this.pqcSig);
|
|
253
295
|
}
|
|
254
296
|
|
|
255
297
|
serialize() {
|
|
@@ -368,19 +410,20 @@ export class PQCAccessListTransaction extends BaseTransaction {
|
|
|
368
410
|
return ethers.keccak256(ethers.hexlify(prefixed));
|
|
369
411
|
}
|
|
370
412
|
|
|
371
|
-
sign(wallet) {
|
|
413
|
+
async sign(wallet) {
|
|
372
414
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
415
|
+
if (!wallet.publicKey) {
|
|
416
|
+
await wallet._ensureKeyPair();
|
|
417
|
+
}
|
|
373
418
|
this.pqcPubKey = wallet.publicKey;
|
|
374
|
-
|
|
375
|
-
this.pqcSig = ml_dsa65.sign(wallet.secretKey, hash, ctx);
|
|
419
|
+
this.pqcSig = await signWithDilithium(wallet.secretKey, hash);
|
|
376
420
|
return this;
|
|
377
421
|
}
|
|
378
422
|
|
|
379
|
-
verify() {
|
|
423
|
+
async verify() {
|
|
380
424
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
381
425
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
382
|
-
|
|
383
|
-
return ml_dsa65.verify(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
426
|
+
return await verifyWithDilithium(this.pqcPubKey, hash, this.pqcSig);
|
|
384
427
|
}
|
|
385
428
|
|
|
386
429
|
serialize() {
|
|
@@ -515,19 +558,20 @@ export class PQCDynamicFeeTransaction extends BaseTransaction {
|
|
|
515
558
|
return ethers.keccak256(ethers.hexlify(prefixed));
|
|
516
559
|
}
|
|
517
560
|
|
|
518
|
-
sign(wallet) {
|
|
561
|
+
async sign(wallet) {
|
|
519
562
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
563
|
+
if (!wallet.publicKey) {
|
|
564
|
+
await wallet._ensureKeyPair();
|
|
565
|
+
}
|
|
520
566
|
this.pqcPubKey = wallet.publicKey;
|
|
521
|
-
|
|
522
|
-
this.pqcSig = ml_dsa65.sign(wallet.secretKey, hash, ctx);
|
|
567
|
+
this.pqcSig = await signWithDilithium(wallet.secretKey, hash);
|
|
523
568
|
return this;
|
|
524
569
|
}
|
|
525
570
|
|
|
526
|
-
verify() {
|
|
571
|
+
async verify() {
|
|
527
572
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
528
573
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
529
|
-
|
|
530
|
-
return ml_dsa65.verify(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
574
|
+
return await verifyWithDilithium(this.pqcPubKey, hash, this.pqcSig);
|
|
531
575
|
}
|
|
532
576
|
|
|
533
577
|
serialize() {
|
package/src/wallet.js
CHANGED
|
@@ -7,20 +7,37 @@ import { ethers } from 'ethers';
|
|
|
7
7
|
import { createRequire } from 'module';
|
|
8
8
|
import { derivePQCAddress, deriveHybridAddress } from './utils/address.js';
|
|
9
9
|
|
|
10
|
-
//
|
|
11
|
-
// This
|
|
12
|
-
//
|
|
10
|
+
// Import dilithium-crystals package
|
|
11
|
+
// This package provides Dilithium3 (ML-DSA-65 equivalent) implementation
|
|
12
|
+
// Use createRequire to handle both ES modules and CommonJS
|
|
13
13
|
const require = createRequire(import.meta.url);
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
// Lazy load dilithium-crystals to avoid top-level await issues
|
|
16
|
+
let dilithiumCache = null;
|
|
17
|
+
|
|
18
|
+
async function getDilithium() {
|
|
19
|
+
if (dilithiumCache) {
|
|
20
|
+
return dilithiumCache;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Try ES module import first
|
|
25
|
+
const dilithiumModule = await import('dilithium-crystals');
|
|
26
|
+
dilithiumCache = dilithiumModule.default || dilithiumModule;
|
|
27
|
+
} catch (e) {
|
|
28
|
+
// Fallback to CommonJS require
|
|
29
|
+
try {
|
|
30
|
+
dilithiumCache = require('dilithium-crystals');
|
|
31
|
+
dilithiumCache = dilithiumCache.default || dilithiumCache;
|
|
32
|
+
} catch (e2) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Failed to import dilithium-crystals: ${e.message}\n` +
|
|
35
|
+
`Please ensure dilithium-crystals is installed: npm install dilithium-crystals`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return dilithiumCache;
|
|
24
41
|
}
|
|
25
42
|
|
|
26
43
|
/**
|
|
@@ -70,12 +87,29 @@ export class PQCWallet {
|
|
|
70
87
|
this.secretKey = secretKey instanceof Uint8Array ? secretKey : new Uint8Array(secretKey);
|
|
71
88
|
this.publicKey = publicKey instanceof Uint8Array ? publicKey : new Uint8Array(publicKey);
|
|
72
89
|
} else {
|
|
73
|
-
// Generate new key pair
|
|
74
|
-
|
|
75
|
-
this.
|
|
76
|
-
this.
|
|
90
|
+
// Generate new key pair - will be done lazily on first use
|
|
91
|
+
this.secretKey = null;
|
|
92
|
+
this.publicKey = null;
|
|
93
|
+
this._keyPairGenerated = false;
|
|
77
94
|
}
|
|
95
|
+
this.address = null; // Will be set after key generation
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Initialize key pair if not already done
|
|
100
|
+
*/
|
|
101
|
+
async _ensureKeyPair() {
|
|
102
|
+
if (this._keyPairGenerated) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const dilithium = await getDilithium();
|
|
107
|
+
// dilithium-crystals typically uses keygen() or generateKeyPair()
|
|
108
|
+
const keyPair = dilithium.keygen ? dilithium.keygen() : dilithium.generateKeyPair();
|
|
109
|
+
this.secretKey = keyPair.secretKey || keyPair.privateKey;
|
|
110
|
+
this.publicKey = keyPair.publicKey;
|
|
78
111
|
this.address = derivePQCAddress(this.publicKey);
|
|
112
|
+
this._keyPairGenerated = true;
|
|
79
113
|
}
|
|
80
114
|
|
|
81
115
|
/**
|
|
@@ -92,43 +126,76 @@ export class PQCWallet {
|
|
|
92
126
|
}
|
|
93
127
|
const secret = secretKey instanceof Uint8Array ? secretKey : ethers.getBytes(secretKey);
|
|
94
128
|
const pub = publicKey instanceof Uint8Array ? publicKey : ethers.getBytes(publicKey);
|
|
95
|
-
|
|
129
|
+
const wallet = new PQCWallet(secret, pub);
|
|
130
|
+
wallet.address = derivePQCAddress(wallet.publicKey);
|
|
131
|
+
wallet._keyPairGenerated = true;
|
|
132
|
+
return wallet;
|
|
96
133
|
}
|
|
97
134
|
|
|
98
135
|
/**
|
|
99
136
|
* Sign a message hash
|
|
100
137
|
* @param {Uint8Array} hash - Message hash (32 bytes)
|
|
101
|
-
* @returns {Uint8Array} Signature
|
|
138
|
+
* @returns {Promise<Uint8Array>} Signature
|
|
102
139
|
*/
|
|
103
|
-
sign(hash) {
|
|
104
|
-
|
|
105
|
-
|
|
140
|
+
async sign(hash) {
|
|
141
|
+
if (!this.secretKey) {
|
|
142
|
+
await this._ensureKeyPair();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const dilithium = await getDilithium();
|
|
146
|
+
// dilithium-crystals API: sign(secretKey, message) or signWithContext(secretKey, message, ctx)
|
|
147
|
+
if (dilithium.sign) {
|
|
148
|
+
return dilithium.sign(this.secretKey, hash);
|
|
149
|
+
} else if (dilithium.signWithContext) {
|
|
150
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
151
|
+
return dilithium.signWithContext(this.secretKey, hash, ctx);
|
|
152
|
+
} else {
|
|
153
|
+
throw new Error('dilithium-crystals does not expose sign method');
|
|
154
|
+
}
|
|
106
155
|
}
|
|
107
156
|
|
|
108
157
|
/**
|
|
109
158
|
* Verify a signature
|
|
110
159
|
* @param {Uint8Array} hash - Message hash
|
|
111
160
|
* @param {Uint8Array} signature - Signature to verify
|
|
112
|
-
* @returns {boolean} True if signature is valid
|
|
161
|
+
* @returns {Promise<boolean>} True if signature is valid
|
|
113
162
|
*/
|
|
114
|
-
verify(hash, signature) {
|
|
115
|
-
|
|
116
|
-
|
|
163
|
+
async verify(hash, signature) {
|
|
164
|
+
if (!this.publicKey) {
|
|
165
|
+
throw new Error('Public key not set');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const dilithium = await getDilithium();
|
|
169
|
+
// dilithium-crystals API: verify(publicKey, message, signature) or verifyWithContext
|
|
170
|
+
if (dilithium.verify) {
|
|
171
|
+
return dilithium.verify(this.publicKey, hash, signature);
|
|
172
|
+
} else if (dilithium.verifyWithContext) {
|
|
173
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
174
|
+
return dilithium.verifyWithContext(this.publicKey, hash, signature, ctx);
|
|
175
|
+
} else {
|
|
176
|
+
throw new Error('dilithium-crystals does not expose verify method');
|
|
177
|
+
}
|
|
117
178
|
}
|
|
118
179
|
|
|
119
180
|
/**
|
|
120
181
|
* Get public key as hex string
|
|
121
|
-
* @returns {string} Public key (hex)
|
|
182
|
+
* @returns {Promise<string>} Public key (hex)
|
|
122
183
|
*/
|
|
123
|
-
getPublicKeyHex() {
|
|
184
|
+
async getPublicKeyHex() {
|
|
185
|
+
if (!this.publicKey) {
|
|
186
|
+
await this._ensureKeyPair();
|
|
187
|
+
}
|
|
124
188
|
return ethers.hexlify(this.publicKey);
|
|
125
189
|
}
|
|
126
190
|
|
|
127
191
|
/**
|
|
128
192
|
* Get secret key as hex string (use with caution!)
|
|
129
|
-
* @returns {string} Secret key (hex)
|
|
193
|
+
* @returns {Promise<string>} Secret key (hex)
|
|
130
194
|
*/
|
|
131
|
-
getSecretKeyHex() {
|
|
195
|
+
async getSecretKeyHex() {
|
|
196
|
+
if (!this.secretKey) {
|
|
197
|
+
await this._ensureKeyPair();
|
|
198
|
+
}
|
|
132
199
|
return ethers.hexlify(this.secretKey);
|
|
133
200
|
}
|
|
134
201
|
}
|
|
@@ -143,10 +210,29 @@ export class HybridWallet {
|
|
|
143
210
|
}
|
|
144
211
|
this.ecdsaWallet = ecdsaWallet instanceof ECDSAWallet ? ecdsaWallet : new ECDSAWallet(ecdsaWallet);
|
|
145
212
|
this.pqcWallet = pqcWallet instanceof PQCWallet ? pqcWallet : new PQCWallet();
|
|
213
|
+
// Address will be computed when PQC wallet is ready
|
|
214
|
+
this.address = null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Get the hybrid address (computed from ECDSA + PQC public keys)
|
|
219
|
+
* @returns {Promise<string>} Hybrid address
|
|
220
|
+
*/
|
|
221
|
+
async getAddress() {
|
|
222
|
+
if (this.address) {
|
|
223
|
+
return this.address;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Ensure PQC wallet has keys
|
|
227
|
+
if (!this.pqcWallet.publicKey) {
|
|
228
|
+
await this.pqcWallet._ensureKeyPair();
|
|
229
|
+
}
|
|
230
|
+
|
|
146
231
|
this.address = deriveHybridAddress(
|
|
147
232
|
ethers.getBytes(this.ecdsaWallet.getPublicKey()),
|
|
148
233
|
this.pqcWallet.publicKey
|
|
149
234
|
);
|
|
235
|
+
return this.address;
|
|
150
236
|
}
|
|
151
237
|
|
|
152
238
|
/**
|
|
@@ -159,7 +245,12 @@ export class HybridWallet {
|
|
|
159
245
|
static fromKeys(ecdsaPrivateKey, pqcSecretKey, pqcPublicKey) {
|
|
160
246
|
const ecdsaWallet = new ECDSAWallet(ecdsaPrivateKey);
|
|
161
247
|
const pqcWallet = new PQCWallet(pqcSecretKey, pqcPublicKey);
|
|
162
|
-
|
|
248
|
+
const wallet = new HybridWallet(ecdsaWallet, pqcWallet);
|
|
249
|
+
wallet.address = deriveHybridAddress(
|
|
250
|
+
ethers.getBytes(ecdsaWallet.getPublicKey()),
|
|
251
|
+
pqcWallet.publicKey
|
|
252
|
+
);
|
|
253
|
+
return wallet;
|
|
163
254
|
}
|
|
164
255
|
|
|
165
256
|
/**
|