@cheny56/node-client 1.0.7 → 1.0.9
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 +4 -7
- package/src/constants.js +11 -4
- package/src/contract.js +9 -4
- package/src/index.js +53 -10
- package/src/provider.js +6 -2
- package/src/transaction.js +93 -36
- package/src/utils/address.js +10 -4
- package/src/utils/rlp.js +10 -4
- package/src/wallet.js +42 -23
- package/src/zk-transaction.js +7 -3
- package/index.cjs +0 -37
package/package.json
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cheny56/node-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Client library for Quorum blockchain with Post-Quantum Cryptography (PQC) and Zero-Knowledge Proof (ZK) support",
|
|
5
|
-
"main": "./index.
|
|
6
|
-
"module": "./src/index.js",
|
|
5
|
+
"main": "./src/index.js",
|
|
7
6
|
"types": "src/index.d.ts",
|
|
8
|
-
"type": "module",
|
|
9
7
|
"exports": {
|
|
10
8
|
".": {
|
|
11
|
-
"require": "./index.
|
|
9
|
+
"require": "./src/index.js",
|
|
12
10
|
"import": "./src/index.js",
|
|
13
11
|
"types": "./src/index.d.ts",
|
|
14
12
|
"default": "./src/index.js"
|
|
@@ -18,7 +16,6 @@
|
|
|
18
16
|
"files": [
|
|
19
17
|
"src/**/*.js",
|
|
20
18
|
"src/**/*.d.ts",
|
|
21
|
-
"index.cjs",
|
|
22
19
|
"package.json",
|
|
23
20
|
"README.md",
|
|
24
21
|
"README-COMMONJS.md",
|
|
@@ -42,7 +39,7 @@
|
|
|
42
39
|
"license": "LGPL-3.0",
|
|
43
40
|
"dependencies": {
|
|
44
41
|
"ethers": "^5.7.2",
|
|
45
|
-
"
|
|
42
|
+
"dilithium-crystals": "^1.0.0"
|
|
46
43
|
},
|
|
47
44
|
"peerDependencies": {},
|
|
48
45
|
"devDependencies": {},
|
package/src/constants.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Transaction Type Constants
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
const TX_TYPE = {
|
|
5
5
|
LEGACY: 0,
|
|
6
6
|
ACCESS_LIST: 1,
|
|
7
7
|
DYNAMIC_FEE: 2,
|
|
@@ -11,7 +11,7 @@ export const TX_TYPE = {
|
|
|
11
11
|
/**
|
|
12
12
|
* PQC Signature Type Constants
|
|
13
13
|
*/
|
|
14
|
-
|
|
14
|
+
const PQC_TYPE = {
|
|
15
15
|
NONE: 0,
|
|
16
16
|
DILITHIUM: 1,
|
|
17
17
|
};
|
|
@@ -19,7 +19,7 @@ export const PQC_TYPE = {
|
|
|
19
19
|
/**
|
|
20
20
|
* ZK Proof System Constants
|
|
21
21
|
*/
|
|
22
|
-
|
|
22
|
+
const ZK_PROOF_SYSTEM = {
|
|
23
23
|
GROTH16: 1,
|
|
24
24
|
PLONK: 2,
|
|
25
25
|
STARK: 3,
|
|
@@ -28,4 +28,11 @@ export const ZK_PROOF_SYSTEM = {
|
|
|
28
28
|
/**
|
|
29
29
|
* Default Chain ID for Quorum
|
|
30
30
|
*/
|
|
31
|
-
|
|
31
|
+
const DEFAULT_CHAIN_ID = 1337;
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
TX_TYPE,
|
|
35
|
+
PQC_TYPE,
|
|
36
|
+
ZK_PROOF_SYSTEM,
|
|
37
|
+
DEFAULT_CHAIN_ID,
|
|
38
|
+
};
|
package/src/contract.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* Supports ERC20 token transfers and contract calls
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const { ethers } = require('ethers');
|
|
7
|
+
const { LegacyTransaction, PQCLegacyTransaction, HybridLegacyTransaction } = require('./transaction.js');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Contract class for interacting with smart contracts
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
class Contract {
|
|
13
13
|
constructor(address, abi, provider, wallet = null) {
|
|
14
14
|
this.address = address;
|
|
15
15
|
this.abi = abi;
|
|
@@ -81,7 +81,7 @@ export class Contract {
|
|
|
81
81
|
* ERC20 Token Contract
|
|
82
82
|
* Simplified interface for ERC20 token operations
|
|
83
83
|
*/
|
|
84
|
-
|
|
84
|
+
class ERC20Token extends Contract {
|
|
85
85
|
constructor(address, provider, wallet = null) {
|
|
86
86
|
const erc20Abi = [
|
|
87
87
|
'function name() view returns (string)',
|
|
@@ -205,3 +205,8 @@ export class ERC20Token extends Contract {
|
|
|
205
205
|
return await provider.sendRawTransaction(serialized);
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
|
+
|
|
209
|
+
module.exports = {
|
|
210
|
+
Contract,
|
|
211
|
+
ERC20Token,
|
|
212
|
+
};
|
package/src/index.js
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// Providers
|
|
7
|
-
|
|
7
|
+
const { QuorumProvider } = require('./provider.js');
|
|
8
8
|
|
|
9
9
|
// Wallets
|
|
10
|
-
|
|
10
|
+
const { ECDSAWallet, PQCWallet, HybridWallet } = require('./wallet.js');
|
|
11
11
|
|
|
12
12
|
// Transactions
|
|
13
|
-
|
|
13
|
+
const {
|
|
14
14
|
LegacyTransaction,
|
|
15
15
|
PQCLegacyTransaction,
|
|
16
16
|
HybridLegacyTransaction,
|
|
@@ -18,20 +18,63 @@ export {
|
|
|
18
18
|
PQCAccessListTransaction,
|
|
19
19
|
DynamicFeeTransaction,
|
|
20
20
|
PQCDynamicFeeTransaction,
|
|
21
|
-
}
|
|
21
|
+
} = require('./transaction.js');
|
|
22
22
|
|
|
23
23
|
// ZK Transactions
|
|
24
|
-
|
|
24
|
+
const { ZKTransaction } = require('./zk-transaction.js');
|
|
25
25
|
|
|
26
26
|
// Contracts
|
|
27
|
-
|
|
27
|
+
const { Contract, ERC20Token } = require('./contract.js');
|
|
28
28
|
|
|
29
29
|
// Constants
|
|
30
|
-
|
|
30
|
+
const { TX_TYPE, PQC_TYPE, ZK_PROOF_SYSTEM, DEFAULT_CHAIN_ID } = require('./constants.js');
|
|
31
31
|
|
|
32
32
|
// Utilities
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
const { derivePQCAddress, deriveHybridAddress, isValidAddress } = require('./utils/address.js');
|
|
34
|
+
const { encodeUint64, encodeBigInt, encodeSignature } = require('./utils/rlp.js');
|
|
35
35
|
|
|
36
36
|
// Re-export ethers utilities for convenience
|
|
37
|
-
|
|
37
|
+
const { ethers } = require('ethers');
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
// Providers
|
|
41
|
+
QuorumProvider,
|
|
42
|
+
|
|
43
|
+
// Wallets
|
|
44
|
+
ECDSAWallet,
|
|
45
|
+
PQCWallet,
|
|
46
|
+
HybridWallet,
|
|
47
|
+
|
|
48
|
+
// Transactions
|
|
49
|
+
LegacyTransaction,
|
|
50
|
+
PQCLegacyTransaction,
|
|
51
|
+
HybridLegacyTransaction,
|
|
52
|
+
AccessListTransaction,
|
|
53
|
+
PQCAccessListTransaction,
|
|
54
|
+
DynamicFeeTransaction,
|
|
55
|
+
PQCDynamicFeeTransaction,
|
|
56
|
+
|
|
57
|
+
// ZK Transactions
|
|
58
|
+
ZKTransaction,
|
|
59
|
+
|
|
60
|
+
// Contracts
|
|
61
|
+
Contract,
|
|
62
|
+
ERC20Token,
|
|
63
|
+
|
|
64
|
+
// Constants
|
|
65
|
+
TX_TYPE,
|
|
66
|
+
PQC_TYPE,
|
|
67
|
+
ZK_PROOF_SYSTEM,
|
|
68
|
+
DEFAULT_CHAIN_ID,
|
|
69
|
+
|
|
70
|
+
// Utilities
|
|
71
|
+
derivePQCAddress,
|
|
72
|
+
deriveHybridAddress,
|
|
73
|
+
isValidAddress,
|
|
74
|
+
encodeUint64,
|
|
75
|
+
encodeBigInt,
|
|
76
|
+
encodeSignature,
|
|
77
|
+
|
|
78
|
+
// Ethers
|
|
79
|
+
ethers,
|
|
80
|
+
};
|
package/src/provider.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* Extends ethers.js JsonRpcProvider with Quorum-specific methods
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
const { ethers } = require('ethers');
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
class QuorumProvider extends ethers.providers.JsonRpcProvider {
|
|
9
9
|
constructor(url, network) {
|
|
10
10
|
super(url, network);
|
|
11
11
|
this.url = url;
|
|
@@ -93,3 +93,7 @@ export class QuorumProvider extends ethers.providers.JsonRpcProvider {
|
|
|
93
93
|
return await super.getBlock(blockNumber);
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
QuorumProvider,
|
|
99
|
+
};
|
package/src/transaction.js
CHANGED
|
@@ -3,23 +3,20 @@
|
|
|
3
3
|
* Supports Legacy, AccessList, DynamicFee transactions with ECDSA, PQC, and Hybrid signatures
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import { encodeUint64, encodeBigInt, encodeSignature } from './utils/rlp.js';
|
|
6
|
+
const { ethers } = require('ethers');
|
|
7
|
+
const { TX_TYPE, PQC_TYPE, DEFAULT_CHAIN_ID } = require('./constants.js');
|
|
8
|
+
const { encodeUint64, encodeBigInt, encodeSignature } = require('./utils/rlp.js');
|
|
10
9
|
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
const require = createRequire(import.meta.url);
|
|
14
|
-
|
|
15
|
-
let ml_dsa65;
|
|
10
|
+
// Import dilithium-crystals package
|
|
11
|
+
let dilithium;
|
|
16
12
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
dilithium = require('dilithium-crystals');
|
|
14
|
+
// Handle both default export and named export patterns
|
|
15
|
+
dilithium = dilithium.default || dilithium;
|
|
19
16
|
} catch (e) {
|
|
20
17
|
throw new Error(
|
|
21
|
-
`Failed to import
|
|
22
|
-
`Please ensure
|
|
18
|
+
`Failed to import dilithium-crystals: ${e.message}\n` +
|
|
19
|
+
`Please ensure dilithium-crystals is installed: npm install dilithium-crystals`
|
|
23
20
|
);
|
|
24
21
|
}
|
|
25
22
|
|
|
@@ -39,7 +36,7 @@ class BaseTransaction {
|
|
|
39
36
|
/**
|
|
40
37
|
* Legacy ECDSA Transaction (Type 0)
|
|
41
38
|
*/
|
|
42
|
-
|
|
39
|
+
class LegacyTransaction extends BaseTransaction {
|
|
43
40
|
constructor(params) {
|
|
44
41
|
super(params);
|
|
45
42
|
this.type = TX_TYPE.LEGACY;
|
|
@@ -79,7 +76,7 @@ export class LegacyTransaction extends BaseTransaction {
|
|
|
79
76
|
/**
|
|
80
77
|
* Legacy PQC-only Transaction (Type 0 with PQC)
|
|
81
78
|
*/
|
|
82
|
-
|
|
79
|
+
class PQCLegacyTransaction extends BaseTransaction {
|
|
83
80
|
constructor(params) {
|
|
84
81
|
super(params);
|
|
85
82
|
this.type = TX_TYPE.LEGACY;
|
|
@@ -126,8 +123,15 @@ export class PQCLegacyTransaction extends BaseTransaction {
|
|
|
126
123
|
sign(wallet) {
|
|
127
124
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
128
125
|
this.pqcPubKey = wallet.publicKey;
|
|
129
|
-
|
|
130
|
-
|
|
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
135
|
this.v = Number(this.chainId) * 2 + 35;
|
|
132
136
|
this.r = '0x0';
|
|
133
137
|
this.s = '0x0';
|
|
@@ -137,8 +141,15 @@ export class PQCLegacyTransaction extends BaseTransaction {
|
|
|
137
141
|
verify() {
|
|
138
142
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
139
143
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
// dilithium-crystals API: verify(publicKey, message, signature) or verifyWithContext
|
|
145
|
+
if (dilithium.verify) {
|
|
146
|
+
return dilithium.verify(this.pqcPubKey, hash, this.pqcSig);
|
|
147
|
+
} else if (dilithium.verifyWithContext) {
|
|
148
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
149
|
+
return dilithium.verifyWithContext(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
150
|
+
} else {
|
|
151
|
+
throw new Error('dilithium-crystals does not expose verify method');
|
|
152
|
+
}
|
|
142
153
|
}
|
|
143
154
|
|
|
144
155
|
serialize() {
|
|
@@ -181,7 +192,7 @@ export class PQCLegacyTransaction extends BaseTransaction {
|
|
|
181
192
|
/**
|
|
182
193
|
* Legacy Hybrid Transaction (Type 0 with ECDSA + PQC)
|
|
183
194
|
*/
|
|
184
|
-
|
|
195
|
+
class HybridLegacyTransaction extends BaseTransaction {
|
|
185
196
|
constructor(params) {
|
|
186
197
|
super(params);
|
|
187
198
|
this.type = TX_TYPE.LEGACY;
|
|
@@ -238,9 +249,15 @@ export class HybridLegacyTransaction extends BaseTransaction {
|
|
|
238
249
|
this.s = ecdsaSig.s;
|
|
239
250
|
|
|
240
251
|
// PQC signature
|
|
241
|
-
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
242
252
|
this.pqcPubKey = pqcWallet.publicKey;
|
|
243
|
-
|
|
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
|
+
}
|
|
244
261
|
|
|
245
262
|
return this;
|
|
246
263
|
}
|
|
@@ -248,8 +265,14 @@ export class HybridLegacyTransaction extends BaseTransaction {
|
|
|
248
265
|
verify() {
|
|
249
266
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
250
267
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
251
|
-
|
|
252
|
-
|
|
268
|
+
if (dilithium.verify) {
|
|
269
|
+
return dilithium.verify(this.pqcPubKey, hash, this.pqcSig);
|
|
270
|
+
} else if (dilithium.verifyWithContext) {
|
|
271
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
272
|
+
return dilithium.verifyWithContext(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
273
|
+
} else {
|
|
274
|
+
throw new Error('dilithium-crystals does not expose verify method');
|
|
275
|
+
}
|
|
253
276
|
}
|
|
254
277
|
|
|
255
278
|
serialize() {
|
|
@@ -292,7 +315,7 @@ export class HybridLegacyTransaction extends BaseTransaction {
|
|
|
292
315
|
/**
|
|
293
316
|
* AccessList Transaction (Type 1) - ECDSA
|
|
294
317
|
*/
|
|
295
|
-
|
|
318
|
+
class AccessListTransaction extends BaseTransaction {
|
|
296
319
|
constructor(params) {
|
|
297
320
|
super(params);
|
|
298
321
|
this.type = TX_TYPE.ACCESS_LIST;
|
|
@@ -324,7 +347,7 @@ export class AccessListTransaction extends BaseTransaction {
|
|
|
324
347
|
/**
|
|
325
348
|
* AccessList PQC Transaction (Type 1 with PQC)
|
|
326
349
|
*/
|
|
327
|
-
|
|
350
|
+
class PQCAccessListTransaction extends BaseTransaction {
|
|
328
351
|
constructor(params) {
|
|
329
352
|
super(params);
|
|
330
353
|
this.type = TX_TYPE.ACCESS_LIST;
|
|
@@ -371,16 +394,28 @@ export class PQCAccessListTransaction extends BaseTransaction {
|
|
|
371
394
|
sign(wallet) {
|
|
372
395
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
373
396
|
this.pqcPubKey = wallet.publicKey;
|
|
374
|
-
|
|
375
|
-
|
|
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
|
+
}
|
|
376
405
|
return this;
|
|
377
406
|
}
|
|
378
407
|
|
|
379
408
|
verify() {
|
|
380
409
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
381
410
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
382
|
-
|
|
383
|
-
|
|
411
|
+
if (dilithium.verify) {
|
|
412
|
+
return dilithium.verify(this.pqcPubKey, hash, this.pqcSig);
|
|
413
|
+
} else if (dilithium.verifyWithContext) {
|
|
414
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
415
|
+
return dilithium.verifyWithContext(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
416
|
+
} else {
|
|
417
|
+
throw new Error('dilithium-crystals does not expose verify method');
|
|
418
|
+
}
|
|
384
419
|
}
|
|
385
420
|
|
|
386
421
|
serialize() {
|
|
@@ -434,7 +469,7 @@ export class PQCAccessListTransaction extends BaseTransaction {
|
|
|
434
469
|
/**
|
|
435
470
|
* DynamicFee Transaction (Type 2) - ECDSA
|
|
436
471
|
*/
|
|
437
|
-
|
|
472
|
+
class DynamicFeeTransaction extends BaseTransaction {
|
|
438
473
|
constructor(params) {
|
|
439
474
|
super(params);
|
|
440
475
|
this.type = TX_TYPE.DYNAMIC_FEE;
|
|
@@ -468,7 +503,7 @@ export class DynamicFeeTransaction extends BaseTransaction {
|
|
|
468
503
|
/**
|
|
469
504
|
* DynamicFee PQC Transaction (Type 2 with PQC)
|
|
470
505
|
*/
|
|
471
|
-
|
|
506
|
+
class PQCDynamicFeeTransaction extends BaseTransaction {
|
|
472
507
|
constructor(params) {
|
|
473
508
|
super(params);
|
|
474
509
|
this.type = TX_TYPE.DYNAMIC_FEE;
|
|
@@ -518,16 +553,28 @@ export class PQCDynamicFeeTransaction extends BaseTransaction {
|
|
|
518
553
|
sign(wallet) {
|
|
519
554
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
520
555
|
this.pqcPubKey = wallet.publicKey;
|
|
521
|
-
|
|
522
|
-
|
|
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
|
+
}
|
|
523
564
|
return this;
|
|
524
565
|
}
|
|
525
566
|
|
|
526
567
|
verify() {
|
|
527
568
|
if (!this.pqcSig || !this.pqcPubKey) return false;
|
|
528
569
|
const hash = ethers.getBytes(this.getSigningHash());
|
|
529
|
-
|
|
530
|
-
|
|
570
|
+
if (dilithium.verify) {
|
|
571
|
+
return dilithium.verify(this.pqcPubKey, hash, this.pqcSig);
|
|
572
|
+
} else if (dilithium.verifyWithContext) {
|
|
573
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
574
|
+
return dilithium.verifyWithContext(this.pqcPubKey, hash, this.pqcSig, ctx);
|
|
575
|
+
} else {
|
|
576
|
+
throw new Error('dilithium-crystals does not expose verify method');
|
|
577
|
+
}
|
|
531
578
|
}
|
|
532
579
|
|
|
533
580
|
serialize() {
|
|
@@ -579,3 +626,13 @@ export class PQCDynamicFeeTransaction extends BaseTransaction {
|
|
|
579
626
|
return ethers.hexlify(this.serialize());
|
|
580
627
|
}
|
|
581
628
|
}
|
|
629
|
+
|
|
630
|
+
module.exports = {
|
|
631
|
+
LegacyTransaction,
|
|
632
|
+
PQCLegacyTransaction,
|
|
633
|
+
HybridLegacyTransaction,
|
|
634
|
+
AccessListTransaction,
|
|
635
|
+
PQCAccessListTransaction,
|
|
636
|
+
DynamicFeeTransaction,
|
|
637
|
+
PQCDynamicFeeTransaction,
|
|
638
|
+
};
|
package/src/utils/address.js
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* Handles address derivation for PQC and Hybrid addresses
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
const { ethers } = require('ethers');
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Derive PQC address from Dilithium public key
|
|
10
10
|
* @param {Uint8Array} publicKey - Dilithium public key
|
|
11
11
|
* @returns {string} Ethereum address
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
function derivePQCAddress(publicKey) {
|
|
14
14
|
const hash = ethers.keccak256(publicKey);
|
|
15
15
|
return ethers.getAddress('0x' + hash.slice(-40));
|
|
16
16
|
}
|
|
@@ -21,7 +21,7 @@ export function derivePQCAddress(publicKey) {
|
|
|
21
21
|
* @param {Uint8Array} dilithiumPublicKey - Dilithium public key
|
|
22
22
|
* @returns {string} Hybrid Ethereum address
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
function deriveHybridAddress(ecdsaPublicKey, dilithiumPublicKey) {
|
|
25
25
|
// Remove 0x04 prefix from ECDSA public key if present
|
|
26
26
|
let ecdsaBytes = ecdsaPublicKey;
|
|
27
27
|
if (ecdsaBytes.length === 65 && ecdsaBytes[0] === 4) {
|
|
@@ -43,6 +43,12 @@ export function deriveHybridAddress(ecdsaPublicKey, dilithiumPublicKey) {
|
|
|
43
43
|
* @param {string} address - Address to validate
|
|
44
44
|
* @returns {boolean}
|
|
45
45
|
*/
|
|
46
|
-
|
|
46
|
+
function isValidAddress(address) {
|
|
47
47
|
return ethers.utils.isAddress(address);
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
module.exports = {
|
|
51
|
+
derivePQCAddress,
|
|
52
|
+
deriveHybridAddress,
|
|
53
|
+
isValidAddress,
|
|
54
|
+
};
|
package/src/utils/rlp.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* Handles proper encoding for Go RLP compatibility
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
const { ethers } = require('ethers');
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Encode uint64 value for RLP as hex string
|
|
10
10
|
* In Go RLP, uint64(0) encodes as empty bytes, non-zero as canonical bytes
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
function encodeUint64(value) {
|
|
13
13
|
if (value === 0 || value === 0n || value === null || value === undefined) {
|
|
14
14
|
return '0x';
|
|
15
15
|
}
|
|
@@ -21,7 +21,7 @@ export function encodeUint64(value) {
|
|
|
21
21
|
* Encode *big.Int value for RLP as hex string
|
|
22
22
|
* Go RLP encodes *big.Int(0) as 0x80 (empty bytes), NOT 0x00!
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
function encodeBigInt(value) {
|
|
25
25
|
if (value === 0 || value === 0n || value === null || value === undefined) {
|
|
26
26
|
return '0x';
|
|
27
27
|
}
|
|
@@ -33,7 +33,7 @@ export function encodeBigInt(value) {
|
|
|
33
33
|
* Encode signature value (R, S) for RLP as hex string
|
|
34
34
|
* Removes leading zeros for canonical form (required for *big.Int in Go RLP)
|
|
35
35
|
*/
|
|
36
|
-
|
|
36
|
+
function encodeSignature(value) {
|
|
37
37
|
if (!value || value === '0x0' || value === '0x' || value === '0x00') {
|
|
38
38
|
return '0x';
|
|
39
39
|
}
|
|
@@ -54,3 +54,9 @@ export function encodeSignature(value) {
|
|
|
54
54
|
bytes = bytes.slice(startIdx);
|
|
55
55
|
return ethers.hexlify(bytes);
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
module.exports = {
|
|
59
|
+
encodeUint64,
|
|
60
|
+
encodeBigInt,
|
|
61
|
+
encodeSignature,
|
|
62
|
+
};
|
package/src/wallet.js
CHANGED
|
@@ -3,30 +3,27 @@
|
|
|
3
3
|
* Supports ECDSA, PQC (Dilithium), and Hybrid wallets
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import { derivePQCAddress, deriveHybridAddress } from './utils/address.js';
|
|
6
|
+
const { ethers } = require('ethers');
|
|
7
|
+
const { derivePQCAddress, deriveHybridAddress } = require('./utils/address.js');
|
|
9
8
|
|
|
10
|
-
//
|
|
11
|
-
// This
|
|
12
|
-
|
|
13
|
-
const require = createRequire(import.meta.url);
|
|
14
|
-
|
|
15
|
-
let ml_dsa65;
|
|
9
|
+
// Import dilithium-crystals package
|
|
10
|
+
// This package provides Dilithium3 (ML-DSA-65 equivalent) implementation
|
|
11
|
+
let dilithium;
|
|
16
12
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
dilithium = require('dilithium-crystals');
|
|
14
|
+
// Handle both default export and named export patterns
|
|
15
|
+
dilithium = dilithium.default || dilithium;
|
|
19
16
|
} catch (e) {
|
|
20
17
|
throw new Error(
|
|
21
|
-
`Failed to import
|
|
22
|
-
`Please ensure
|
|
18
|
+
`Failed to import dilithium-crystals: ${e.message}\n` +
|
|
19
|
+
`Please ensure dilithium-crystals is installed: npm install dilithium-crystals`
|
|
23
20
|
);
|
|
24
21
|
}
|
|
25
22
|
|
|
26
23
|
/**
|
|
27
24
|
* ECDSA Wallet (standard Ethereum wallet)
|
|
28
25
|
*/
|
|
29
|
-
|
|
26
|
+
class ECDSAWallet {
|
|
30
27
|
constructor(privateKey, provider = null) {
|
|
31
28
|
this.wallet = new ethers.Wallet(privateKey, provider);
|
|
32
29
|
this.address = this.wallet.address;
|
|
@@ -64,15 +61,16 @@ export class ECDSAWallet {
|
|
|
64
61
|
/**
|
|
65
62
|
* PQC Wallet (Dilithium/ML-DSA-65)
|
|
66
63
|
*/
|
|
67
|
-
|
|
64
|
+
class PQCWallet {
|
|
68
65
|
constructor(secretKey = null, publicKey = null) {
|
|
69
66
|
if (secretKey && publicKey) {
|
|
70
67
|
this.secretKey = secretKey instanceof Uint8Array ? secretKey : new Uint8Array(secretKey);
|
|
71
68
|
this.publicKey = publicKey instanceof Uint8Array ? publicKey : new Uint8Array(publicKey);
|
|
72
69
|
} else {
|
|
73
|
-
// Generate new key pair
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
// 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;
|
|
76
74
|
this.publicKey = keyPair.publicKey;
|
|
77
75
|
}
|
|
78
76
|
this.address = derivePQCAddress(this.publicKey);
|
|
@@ -101,8 +99,16 @@ export class PQCWallet {
|
|
|
101
99
|
* @returns {Uint8Array} Signature
|
|
102
100
|
*/
|
|
103
101
|
sign(hash) {
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
// dilithium-crystals API: sign(secretKey, message)
|
|
103
|
+
// Some implementations may require context, but we'll try without first
|
|
104
|
+
if (dilithium.sign) {
|
|
105
|
+
return dilithium.sign(this.secretKey, hash);
|
|
106
|
+
} else if (dilithium.signWithContext) {
|
|
107
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
108
|
+
return dilithium.signWithContext(this.secretKey, hash, ctx);
|
|
109
|
+
} else {
|
|
110
|
+
throw new Error('dilithium-crystals does not expose sign method');
|
|
111
|
+
}
|
|
106
112
|
}
|
|
107
113
|
|
|
108
114
|
/**
|
|
@@ -112,8 +118,15 @@ export class PQCWallet {
|
|
|
112
118
|
* @returns {boolean} True if signature is valid
|
|
113
119
|
*/
|
|
114
120
|
verify(hash, signature) {
|
|
115
|
-
|
|
116
|
-
|
|
121
|
+
// dilithium-crystals API: verify(publicKey, message, signature)
|
|
122
|
+
if (dilithium.verify) {
|
|
123
|
+
return dilithium.verify(this.publicKey, hash, signature);
|
|
124
|
+
} else if (dilithium.verifyWithContext) {
|
|
125
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
126
|
+
return dilithium.verifyWithContext(this.publicKey, hash, signature, ctx);
|
|
127
|
+
} else {
|
|
128
|
+
throw new Error('dilithium-crystals does not expose verify method');
|
|
129
|
+
}
|
|
117
130
|
}
|
|
118
131
|
|
|
119
132
|
/**
|
|
@@ -136,7 +149,7 @@ export class PQCWallet {
|
|
|
136
149
|
/**
|
|
137
150
|
* Hybrid Wallet (ECDSA + PQC)
|
|
138
151
|
*/
|
|
139
|
-
|
|
152
|
+
class HybridWallet {
|
|
140
153
|
constructor(ecdsaWallet, pqcWallet) {
|
|
141
154
|
if (!ecdsaWallet || !pqcWallet) {
|
|
142
155
|
throw new Error('Both ECDSA and PQC wallets are required for Hybrid wallet');
|
|
@@ -172,3 +185,9 @@ export class HybridWallet {
|
|
|
172
185
|
return new HybridWallet(connectedECDSA, this.pqcWallet);
|
|
173
186
|
}
|
|
174
187
|
}
|
|
188
|
+
|
|
189
|
+
module.exports = {
|
|
190
|
+
ECDSAWallet,
|
|
191
|
+
PQCWallet,
|
|
192
|
+
HybridWallet,
|
|
193
|
+
};
|
package/src/zk-transaction.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* Zero-Knowledge Proof Transaction Support
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const { ethers } = require('ethers');
|
|
6
|
+
const { TX_TYPE, ZK_PROOF_SYSTEM } = require('./constants.js');
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* ZK Transaction Builder
|
|
10
10
|
* Creates transactions with zero-knowledge proofs
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
class ZKTransaction {
|
|
13
13
|
constructor(params) {
|
|
14
14
|
this.type = TX_TYPE.ZK_PRIVATE;
|
|
15
15
|
this.chainId = params.chainId || 1337;
|
|
@@ -93,3 +93,7 @@ export class ZKTransaction {
|
|
|
93
93
|
return await provider.send('quorum_sendZKTransaction', [args]);
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
ZKTransaction,
|
|
99
|
+
};
|
package/index.cjs
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CommonJS entry point for @cheny56/node-client
|
|
3
|
-
*
|
|
4
|
-
* NOTE: This library is built as ES modules. For CommonJS compatibility,
|
|
5
|
-
* you need to use dynamic import() instead of require().
|
|
6
|
-
*
|
|
7
|
-
* Example:
|
|
8
|
-
* const { QuorumProvider } = await import('@cheny56/node-client');
|
|
9
|
-
*
|
|
10
|
-
* Or use ES modules in your project:
|
|
11
|
-
* import { QuorumProvider } from '@cheny56/node-client';
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
// Re-export using dynamic import
|
|
15
|
-
// This allows require() to work, but returns a Promise
|
|
16
|
-
const modPromise = import('./src/index.js');
|
|
17
|
-
|
|
18
|
-
// For synchronous require(), we need to throw a helpful error
|
|
19
|
-
// and suggest using import() or ES modules
|
|
20
|
-
module.exports = new Proxy({}, {
|
|
21
|
-
get(target, prop) {
|
|
22
|
-
if (prop === 'then' || prop === 'catch' || prop === 'finally') {
|
|
23
|
-
// Make it thenable so it works with await import()
|
|
24
|
-
return modPromise.then(mod => mod[prop]).bind(modPromise);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
throw new Error(
|
|
28
|
-
`Cannot access '${prop}' synchronously. ` +
|
|
29
|
-
`This package uses ES modules. Please use:\n` +
|
|
30
|
-
` const { ${prop} } = await import('@cheny56/node-client');\n` +
|
|
31
|
-
`Or switch your project to ES modules by adding "type": "module" to package.json`
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Also export as a Promise for await import() usage
|
|
37
|
-
module.exports.default = modPromise;
|