@cheny56/node-client 1.0.6 → 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 +87 -29
- package/src/wallet.js +126 -20
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
|
@@ -4,11 +4,68 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { ethers } from 'ethers';
|
|
7
|
-
|
|
8
|
-
import { ml_dsa65 } from '@noble/post-quantum/ml-dsa';
|
|
7
|
+
import { createRequire } from 'module';
|
|
9
8
|
import { TX_TYPE, PQC_TYPE, DEFAULT_CHAIN_ID } from './constants.js';
|
|
10
9
|
import { encodeUint64, encodeBigInt, encodeSignature } from './utils/rlp.js';
|
|
11
10
|
|
|
11
|
+
// Import dilithium-crystals package
|
|
12
|
+
// Use createRequire to handle both ES modules and CommonJS
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
|
|
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
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
12
69
|
/**
|
|
13
70
|
* Base Transaction class
|
|
14
71
|
*/
|
|
@@ -107,24 +164,22 @@ export class PQCLegacyTransaction extends BaseTransaction {
|
|
|
107
164
|
/**
|
|
108
165
|
* Sign with PQC wallet
|
|
109
166
|
* @param {PQCWallet} wallet - PQC wallet
|
|
110
|
-
* @returns {PQCLegacyTransaction} This transaction
|
|
167
|
+
* @returns {Promise<PQCLegacyTransaction>} This transaction
|
|
111
168
|
*/
|
|
112
|
-
sign(wallet) {
|
|
169
|
+
async sign(wallet) {
|
|
113
170
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
114
|
-
this.pqcPubKey = wallet.publicKey;
|
|
115
|
-
|
|
116
|
-
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);
|
|
117
173
|
this.v = Number(this.chainId) * 2 + 35;
|
|
118
174
|
this.r = '0x0';
|
|
119
175
|
this.s = '0x0';
|
|
120
176
|
return this;
|
|
121
177
|
}
|
|
122
178
|
|
|
123
|
-
verify() {
|
|
179
|
+
async verify() {
|
|
124
180
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
125
181
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
126
|
-
|
|
127
|
-
return ml_dsa65.verify(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
182
|
+
return await verifyWithDilithium(this.pqcPubKey, hash, this.pqcSig);
|
|
128
183
|
}
|
|
129
184
|
|
|
130
185
|
serialize() {
|
|
@@ -210,9 +265,9 @@ export class HybridLegacyTransaction extends BaseTransaction {
|
|
|
210
265
|
* Sign with both ECDSA and PQC wallets
|
|
211
266
|
* @param {ECDSAWallet} ecdsaWallet - ECDSA wallet
|
|
212
267
|
* @param {PQCWallet} pqcWallet - PQC wallet
|
|
213
|
-
* @returns {HybridLegacyTransaction} This transaction
|
|
268
|
+
* @returns {Promise<HybridLegacyTransaction>} This transaction
|
|
214
269
|
*/
|
|
215
|
-
sign(ecdsaWallet, pqcWallet) {
|
|
270
|
+
async sign(ecdsaWallet, pqcWallet) {
|
|
216
271
|
const hash = this.getSigningHash();
|
|
217
272
|
const hashBytes = ethers.getBytes(hash);
|
|
218
273
|
|
|
@@ -224,18 +279,19 @@ export class HybridLegacyTransaction extends BaseTransaction {
|
|
|
224
279
|
this.s = ecdsaSig.s;
|
|
225
280
|
|
|
226
281
|
// PQC signature
|
|
227
|
-
|
|
282
|
+
if (!pqcWallet.publicKey) {
|
|
283
|
+
await pqcWallet._ensureKeyPair();
|
|
284
|
+
}
|
|
228
285
|
this.pqcPubKey = pqcWallet.publicKey;
|
|
229
|
-
this.pqcSig =
|
|
286
|
+
this.pqcSig = await signWithDilithium(pqcWallet.secretKey, hashBytes);
|
|
230
287
|
|
|
231
288
|
return this;
|
|
232
289
|
}
|
|
233
290
|
|
|
234
|
-
verify() {
|
|
291
|
+
async verify() {
|
|
235
292
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
236
293
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
237
|
-
|
|
238
|
-
return ml_dsa65.verify(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
294
|
+
return await verifyWithDilithium(this.pqcPubKey, hash, this.pqcSig);
|
|
239
295
|
}
|
|
240
296
|
|
|
241
297
|
serialize() {
|
|
@@ -354,19 +410,20 @@ export class PQCAccessListTransaction extends BaseTransaction {
|
|
|
354
410
|
return ethers.keccak256(ethers.hexlify(prefixed));
|
|
355
411
|
}
|
|
356
412
|
|
|
357
|
-
sign(wallet) {
|
|
413
|
+
async sign(wallet) {
|
|
358
414
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
415
|
+
if (!wallet.publicKey) {
|
|
416
|
+
await wallet._ensureKeyPair();
|
|
417
|
+
}
|
|
359
418
|
this.pqcPubKey = wallet.publicKey;
|
|
360
|
-
|
|
361
|
-
this.pqcSig = ml_dsa65.sign(wallet.secretKey, hash, ctx);
|
|
419
|
+
this.pqcSig = await signWithDilithium(wallet.secretKey, hash);
|
|
362
420
|
return this;
|
|
363
421
|
}
|
|
364
422
|
|
|
365
|
-
verify() {
|
|
423
|
+
async verify() {
|
|
366
424
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
367
425
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
368
|
-
|
|
369
|
-
return ml_dsa65.verify(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
426
|
+
return await verifyWithDilithium(this.pqcPubKey, hash, this.pqcSig);
|
|
370
427
|
}
|
|
371
428
|
|
|
372
429
|
serialize() {
|
|
@@ -501,19 +558,20 @@ export class PQCDynamicFeeTransaction extends BaseTransaction {
|
|
|
501
558
|
return ethers.keccak256(ethers.hexlify(prefixed));
|
|
502
559
|
}
|
|
503
560
|
|
|
504
|
-
sign(wallet) {
|
|
561
|
+
async sign(wallet) {
|
|
505
562
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
563
|
+
if (!wallet.publicKey) {
|
|
564
|
+
await wallet._ensureKeyPair();
|
|
565
|
+
}
|
|
506
566
|
this.pqcPubKey = wallet.publicKey;
|
|
507
|
-
|
|
508
|
-
this.pqcSig = ml_dsa65.sign(wallet.secretKey, hash, ctx);
|
|
567
|
+
this.pqcSig = await signWithDilithium(wallet.secretKey, hash);
|
|
509
568
|
return this;
|
|
510
569
|
}
|
|
511
570
|
|
|
512
|
-
verify() {
|
|
571
|
+
async verify() {
|
|
513
572
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
514
573
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
515
|
-
|
|
516
|
-
return ml_dsa65.verify(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
574
|
+
return await verifyWithDilithium(this.pqcPubKey, hash, this.pqcSig);
|
|
517
575
|
}
|
|
518
576
|
|
|
519
577
|
serialize() {
|
package/src/wallet.js
CHANGED
|
@@ -4,10 +4,42 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { ethers } from 'ethers';
|
|
7
|
-
|
|
8
|
-
import { ml_dsa65 } from '@noble/post-quantum/ml-dsa';
|
|
7
|
+
import { createRequire } from 'module';
|
|
9
8
|
import { derivePQCAddress, deriveHybridAddress } from './utils/address.js';
|
|
10
9
|
|
|
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
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
|
|
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
|
+
|
|
11
43
|
/**
|
|
12
44
|
* ECDSA Wallet (standard Ethereum wallet)
|
|
13
45
|
*/
|
|
@@ -55,12 +87,29 @@ export class PQCWallet {
|
|
|
55
87
|
this.secretKey = secretKey instanceof Uint8Array ? secretKey : new Uint8Array(secretKey);
|
|
56
88
|
this.publicKey = publicKey instanceof Uint8Array ? publicKey : new Uint8Array(publicKey);
|
|
57
89
|
} else {
|
|
58
|
-
// Generate new key pair
|
|
59
|
-
|
|
60
|
-
this.
|
|
61
|
-
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;
|
|
62
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;
|
|
63
111
|
this.address = derivePQCAddress(this.publicKey);
|
|
112
|
+
this._keyPairGenerated = true;
|
|
64
113
|
}
|
|
65
114
|
|
|
66
115
|
/**
|
|
@@ -77,43 +126,76 @@ export class PQCWallet {
|
|
|
77
126
|
}
|
|
78
127
|
const secret = secretKey instanceof Uint8Array ? secretKey : ethers.getBytes(secretKey);
|
|
79
128
|
const pub = publicKey instanceof Uint8Array ? publicKey : ethers.getBytes(publicKey);
|
|
80
|
-
|
|
129
|
+
const wallet = new PQCWallet(secret, pub);
|
|
130
|
+
wallet.address = derivePQCAddress(wallet.publicKey);
|
|
131
|
+
wallet._keyPairGenerated = true;
|
|
132
|
+
return wallet;
|
|
81
133
|
}
|
|
82
134
|
|
|
83
135
|
/**
|
|
84
136
|
* Sign a message hash
|
|
85
137
|
* @param {Uint8Array} hash - Message hash (32 bytes)
|
|
86
|
-
* @returns {Uint8Array} Signature
|
|
138
|
+
* @returns {Promise<Uint8Array>} Signature
|
|
87
139
|
*/
|
|
88
|
-
sign(hash) {
|
|
89
|
-
|
|
90
|
-
|
|
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
|
+
}
|
|
91
155
|
}
|
|
92
156
|
|
|
93
157
|
/**
|
|
94
158
|
* Verify a signature
|
|
95
159
|
* @param {Uint8Array} hash - Message hash
|
|
96
160
|
* @param {Uint8Array} signature - Signature to verify
|
|
97
|
-
* @returns {boolean} True if signature is valid
|
|
161
|
+
* @returns {Promise<boolean>} True if signature is valid
|
|
98
162
|
*/
|
|
99
|
-
verify(hash, signature) {
|
|
100
|
-
|
|
101
|
-
|
|
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
|
+
}
|
|
102
178
|
}
|
|
103
179
|
|
|
104
180
|
/**
|
|
105
181
|
* Get public key as hex string
|
|
106
|
-
* @returns {string} Public key (hex)
|
|
182
|
+
* @returns {Promise<string>} Public key (hex)
|
|
107
183
|
*/
|
|
108
|
-
getPublicKeyHex() {
|
|
184
|
+
async getPublicKeyHex() {
|
|
185
|
+
if (!this.publicKey) {
|
|
186
|
+
await this._ensureKeyPair();
|
|
187
|
+
}
|
|
109
188
|
return ethers.hexlify(this.publicKey);
|
|
110
189
|
}
|
|
111
190
|
|
|
112
191
|
/**
|
|
113
192
|
* Get secret key as hex string (use with caution!)
|
|
114
|
-
* @returns {string} Secret key (hex)
|
|
193
|
+
* @returns {Promise<string>} Secret key (hex)
|
|
115
194
|
*/
|
|
116
|
-
getSecretKeyHex() {
|
|
195
|
+
async getSecretKeyHex() {
|
|
196
|
+
if (!this.secretKey) {
|
|
197
|
+
await this._ensureKeyPair();
|
|
198
|
+
}
|
|
117
199
|
return ethers.hexlify(this.secretKey);
|
|
118
200
|
}
|
|
119
201
|
}
|
|
@@ -128,10 +210,29 @@ export class HybridWallet {
|
|
|
128
210
|
}
|
|
129
211
|
this.ecdsaWallet = ecdsaWallet instanceof ECDSAWallet ? ecdsaWallet : new ECDSAWallet(ecdsaWallet);
|
|
130
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
|
+
|
|
131
231
|
this.address = deriveHybridAddress(
|
|
132
232
|
ethers.getBytes(this.ecdsaWallet.getPublicKey()),
|
|
133
233
|
this.pqcWallet.publicKey
|
|
134
234
|
);
|
|
235
|
+
return this.address;
|
|
135
236
|
}
|
|
136
237
|
|
|
137
238
|
/**
|
|
@@ -144,7 +245,12 @@ export class HybridWallet {
|
|
|
144
245
|
static fromKeys(ecdsaPrivateKey, pqcSecretKey, pqcPublicKey) {
|
|
145
246
|
const ecdsaWallet = new ECDSAWallet(ecdsaPrivateKey);
|
|
146
247
|
const pqcWallet = new PQCWallet(pqcSecretKey, pqcPublicKey);
|
|
147
|
-
|
|
248
|
+
const wallet = new HybridWallet(ecdsaWallet, pqcWallet);
|
|
249
|
+
wallet.address = deriveHybridAddress(
|
|
250
|
+
ethers.getBytes(ecdsaWallet.getPublicKey()),
|
|
251
|
+
pqcWallet.publicKey
|
|
252
|
+
);
|
|
253
|
+
return wallet;
|
|
148
254
|
}
|
|
149
255
|
|
|
150
256
|
/**
|