@cheny56/node-client 1.0.9 → 1.0.11

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cheny56/node-client",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Client library for Quorum blockchain with Post-Quantum Cryptography (PQC) and Zero-Knowledge Proof (ZK) support",
5
5
  "main": "./src/index.js",
6
6
  "types": "src/index.d.ts",
package/src/contract.js CHANGED
@@ -160,6 +160,10 @@ 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 is initialized
164
+ if (!wallet._initialized) {
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 @@ 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 @@ 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
- const nonce = await provider.getTransactionCount(wallet.address, 'pending');
195
+ // Ensure wallet is initialized
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 @@ 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
  }
@@ -118,30 +118,28 @@ class PQCLegacyTransaction extends BaseTransaction {
118
118
  /**
119
119
  * Sign with PQC wallet
120
120
  * @param {PQCWallet} wallet - PQC wallet
121
- * @returns {PQCLegacyTransaction} This transaction
121
+ * @returns {Promise<PQCLegacyTransaction>} This transaction
122
122
  */
123
- sign(wallet) {
123
+ async sign(wallet) {
124
+ // Ensure wallet is initialized
125
+ if (!wallet._initialized) {
126
+ await wallet._ensureKeyPair();
127
+ }
128
+
124
129
  const hash = ethers.getBytes(this.getSigningHash());
125
130
  this.pqcPubKey = wallet.publicKey;
126
- // dilithium-crystals API: sign(secretKey, message) or signWithContext(secretKey, message, ctx)
127
- if (dilithium.sign) {
128
- this.pqcSig = dilithium.sign(wallet.secretKey, hash);
129
- } else if (dilithium.signWithContext) {
130
- const ctx = new TextEncoder().encode('ML-DSA-65');
131
- this.pqcSig = dilithium.signWithContext(wallet.secretKey, hash, ctx);
132
- } else {
133
- throw new Error('dilithium-crystals does not expose sign method');
134
- }
131
+ // Use wallet's sign method which handles the async properly
132
+ this.pqcSig = await wallet.sign(hash);
135
133
  this.v = Number(this.chainId) * 2 + 35;
136
134
  this.r = '0x0';
137
135
  this.s = '0x0';
138
136
  return this;
139
137
  }
140
138
 
141
- verify() {
139
+ async verify() {
142
140
  if (!this.pqcSig || !this.pqcPubKey) return false;
143
141
  const hash = ethers.getBytes(this.getSigningHash());
144
- // dilithium-crystals API: verify(publicKey, message, signature) or verifyWithContext
142
+ // Use dilithium verify directly
145
143
  if (dilithium.verify) {
146
144
  return dilithium.verify(this.pqcPubKey, hash, this.pqcSig);
147
145
  } else if (dilithium.verifyWithContext) {
@@ -235,9 +233,14 @@ class HybridLegacyTransaction extends BaseTransaction {
235
233
  * Sign with both ECDSA and PQC wallets
236
234
  * @param {ECDSAWallet} ecdsaWallet - ECDSA wallet
237
235
  * @param {PQCWallet} pqcWallet - PQC wallet
238
- * @returns {HybridLegacyTransaction} This transaction
236
+ * @returns {Promise<HybridLegacyTransaction>} This transaction
239
237
  */
240
- sign(ecdsaWallet, pqcWallet) {
238
+ async sign(ecdsaWallet, pqcWallet) {
239
+ // Ensure PQC wallet is initialized
240
+ if (!pqcWallet._initialized) {
241
+ await pqcWallet._ensureKeyPair();
242
+ }
243
+
241
244
  const hash = this.getSigningHash();
242
245
  const hashBytes = ethers.getBytes(hash);
243
246
 
@@ -248,16 +251,9 @@ class HybridLegacyTransaction extends BaseTransaction {
248
251
  this.r = ecdsaSig.r;
249
252
  this.s = ecdsaSig.s;
250
253
 
251
- // PQC signature
254
+ // PQC signature - use wallet's sign method
252
255
  this.pqcPubKey = pqcWallet.publicKey;
253
- if (dilithium.sign) {
254
- this.pqcSig = dilithium.sign(pqcWallet.secretKey, hashBytes);
255
- } else if (dilithium.signWithContext) {
256
- const ctx = new TextEncoder().encode('ML-DSA-65');
257
- this.pqcSig = dilithium.signWithContext(pqcWallet.secretKey, hashBytes, ctx);
258
- } else {
259
- throw new Error('dilithium-crystals does not expose sign method');
260
- }
256
+ this.pqcSig = await pqcWallet.sign(hashBytes);
261
257
 
262
258
  return this;
263
259
  }
@@ -391,21 +387,19 @@ class PQCAccessListTransaction extends BaseTransaction {
391
387
  return ethers.keccak256(ethers.hexlify(prefixed));
392
388
  }
393
389
 
394
- sign(wallet) {
390
+ async sign(wallet) {
391
+ // Ensure wallet is initialized
392
+ if (!wallet._initialized) {
393
+ await wallet._ensureKeyPair();
394
+ }
395
+
395
396
  const hash = ethers.getBytes(this.getSigningHash());
396
397
  this.pqcPubKey = wallet.publicKey;
397
- if (dilithium.sign) {
398
- this.pqcSig = dilithium.sign(wallet.secretKey, hash);
399
- } else if (dilithium.signWithContext) {
400
- const ctx = new TextEncoder().encode('ML-DSA-65');
401
- this.pqcSig = dilithium.signWithContext(wallet.secretKey, hash, ctx);
402
- } else {
403
- throw new Error('dilithium-crystals does not expose sign method');
404
- }
398
+ this.pqcSig = await wallet.sign(hash);
405
399
  return this;
406
400
  }
407
401
 
408
- verify() {
402
+ async verify() {
409
403
  if (!this.pqcSig || !this.pqcPubKey) return false;
410
404
  const hash = ethers.getBytes(this.getSigningHash());
411
405
  if (dilithium.verify) {
@@ -550,21 +544,19 @@ class PQCDynamicFeeTransaction extends BaseTransaction {
550
544
  return ethers.keccak256(ethers.hexlify(prefixed));
551
545
  }
552
546
 
553
- sign(wallet) {
547
+ async sign(wallet) {
548
+ // Ensure wallet is initialized
549
+ if (!wallet._initialized) {
550
+ await wallet._ensureKeyPair();
551
+ }
552
+
554
553
  const hash = ethers.getBytes(this.getSigningHash());
555
554
  this.pqcPubKey = wallet.publicKey;
556
- if (dilithium.sign) {
557
- this.pqcSig = dilithium.sign(wallet.secretKey, hash);
558
- } else if (dilithium.signWithContext) {
559
- const ctx = new TextEncoder().encode('ML-DSA-65');
560
- this.pqcSig = dilithium.signWithContext(wallet.secretKey, hash, ctx);
561
- } else {
562
- throw new Error('dilithium-crystals does not expose sign method');
563
- }
555
+ this.pqcSig = await wallet.sign(hash);
564
556
  return this;
565
557
  }
566
558
 
567
- verify() {
559
+ async verify() {
568
560
  if (!this.pqcSig || !this.pqcPubKey) return false;
569
561
  const hash = ethers.getBytes(this.getSigningHash());
570
562
  if (dilithium.verify) {
package/src/wallet.js CHANGED
@@ -66,14 +66,36 @@ class PQCWallet {
66
66
  if (secretKey && publicKey) {
67
67
  this.secretKey = secretKey instanceof Uint8Array ? secretKey : new Uint8Array(secretKey);
68
68
  this.publicKey = publicKey instanceof Uint8Array ? publicKey : new Uint8Array(publicKey);
69
+ this.address = derivePQCAddress(this.publicKey);
70
+ this._initialized = true;
69
71
  } else {
70
72
  // Generate new key pair using dilithium-crystals
71
- // dilithium-crystals typically uses keygen() or generateKeyPair()
72
- const keyPair = dilithium.keygen ? dilithium.keygen() : dilithium.generateKeyPair();
73
- this.secretKey = keyPair.secretKey || keyPair.privateKey;
74
- this.publicKey = keyPair.publicKey;
73
+ // dilithium-crystals uses keyPair() which is async and returns { publicKey, secretKey }
74
+ this.secretKey = null;
75
+ this.publicKey = null;
76
+ this.address = null;
77
+ this._initialized = false;
75
78
  }
79
+ }
80
+
81
+ /**
82
+ * Initialize key pair if not already done (async)
83
+ * @private
84
+ */
85
+ async _ensureKeyPair() {
86
+ if (this._initialized) {
87
+ return;
88
+ }
89
+
90
+ if (!dilithium.keyPair) {
91
+ throw new Error('dilithium-crystals does not expose keyPair method. Please check the package API.');
92
+ }
93
+
94
+ const keyPair = await dilithium.keyPair();
95
+ this.secretKey = keyPair.secretKey;
96
+ this.publicKey = keyPair.publicKey;
76
97
  this.address = derivePQCAddress(this.publicKey);
98
+ this._initialized = true;
77
99
  }
78
100
 
79
101
  /**
@@ -96,9 +118,14 @@ class PQCWallet {
96
118
  /**
97
119
  * Sign a message hash
98
120
  * @param {Uint8Array} hash - Message hash (32 bytes)
99
- * @returns {Uint8Array} Signature
121
+ * @returns {Promise<Uint8Array>} Signature
100
122
  */
101
- sign(hash) {
123
+ async sign(hash) {
124
+ // Ensure key pair is initialized
125
+ if (!this._initialized) {
126
+ await this._ensureKeyPair();
127
+ }
128
+
102
129
  // dilithium-crystals API: sign(secretKey, message)
103
130
  // Some implementations may require context, but we'll try without first
104
131
  if (dilithium.sign) {
@@ -115,9 +142,14 @@ class PQCWallet {
115
142
  * Verify a signature
116
143
  * @param {Uint8Array} hash - Message hash
117
144
  * @param {Uint8Array} signature - Signature to verify
118
- * @returns {boolean} True if signature is valid
145
+ * @returns {Promise<boolean>} True if signature is valid
119
146
  */
120
- verify(hash, signature) {
147
+ async verify(hash, signature) {
148
+ // Ensure key pair is initialized
149
+ if (!this._initialized) {
150
+ await this._ensureKeyPair();
151
+ }
152
+
121
153
  // dilithium-crystals API: verify(publicKey, message, signature)
122
154
  if (dilithium.verify) {
123
155
  return dilithium.verify(this.publicKey, hash, signature);
@@ -131,17 +163,23 @@ class PQCWallet {
131
163
 
132
164
  /**
133
165
  * Get public key as hex string
134
- * @returns {string} Public key (hex)
166
+ * @returns {Promise<string>} Public key (hex)
135
167
  */
136
- getPublicKeyHex() {
168
+ async getPublicKeyHex() {
169
+ if (!this._initialized) {
170
+ await this._ensureKeyPair();
171
+ }
137
172
  return ethers.hexlify(this.publicKey);
138
173
  }
139
174
 
140
175
  /**
141
176
  * Get secret key as hex string (use with caution!)
142
- * @returns {string} Secret key (hex)
177
+ * @returns {Promise<string>} Secret key (hex)
143
178
  */
144
- getSecretKeyHex() {
179
+ async getSecretKeyHex() {
180
+ if (!this._initialized) {
181
+ await this._ensureKeyPair();
182
+ }
145
183
  return ethers.hexlify(this.secretKey);
146
184
  }
147
185
  }
@@ -156,10 +194,30 @@ class HybridWallet {
156
194
  }
157
195
  this.ecdsaWallet = ecdsaWallet instanceof ECDSAWallet ? ecdsaWallet : new ECDSAWallet(ecdsaWallet);
158
196
  this.pqcWallet = pqcWallet instanceof PQCWallet ? pqcWallet : new PQCWallet();
197
+ this.address = null; // Will be computed when PQC wallet is initialized
198
+ this._initialized = false;
199
+ }
200
+
201
+ /**
202
+ * Get the hybrid address (computed from ECDSA + PQC public keys)
203
+ * @returns {Promise<string>} Hybrid address
204
+ */
205
+ async getAddress() {
206
+ if (this._initialized && this.address) {
207
+ return this.address;
208
+ }
209
+
210
+ // Ensure PQC wallet has keys
211
+ if (!this.pqcWallet._initialized) {
212
+ await this.pqcWallet._ensureKeyPair();
213
+ }
214
+
159
215
  this.address = deriveHybridAddress(
160
216
  ethers.getBytes(this.ecdsaWallet.getPublicKey()),
161
217
  this.pqcWallet.publicKey
162
218
  );
219
+ this._initialized = true;
220
+ return this.address;
163
221
  }
164
222
 
165
223
  /**
@@ -172,7 +230,13 @@ class HybridWallet {
172
230
  static fromKeys(ecdsaPrivateKey, pqcSecretKey, pqcPublicKey) {
173
231
  const ecdsaWallet = new ECDSAWallet(ecdsaPrivateKey);
174
232
  const pqcWallet = new PQCWallet(pqcSecretKey, pqcPublicKey);
175
- return new HybridWallet(ecdsaWallet, pqcWallet);
233
+ const wallet = new HybridWallet(ecdsaWallet, pqcWallet);
234
+ wallet.address = deriveHybridAddress(
235
+ ethers.getBytes(ecdsaWallet.getPublicKey()),
236
+ pqcWallet.publicKey
237
+ );
238
+ wallet._initialized = true;
239
+ return wallet;
176
240
  }
177
241
 
178
242
  /**