@cheny56/node-client 1.0.0
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/README.md +293 -0
- package/package.json +32 -0
- package/src/constants.js +31 -0
- package/src/contract.js +207 -0
- package/src/index.js +37 -0
- package/src/provider.js +95 -0
- package/src/transaction.js +566 -0
- package/src/utils/address.js +48 -0
- package/src/utils/rlp.js +56 -0
- package/src/wallet.js +158 -0
- package/src/zk-transaction.js +95 -0
package/src/wallet.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet Classes
|
|
3
|
+
* Supports ECDSA, PQC (Dilithium), and Hybrid wallets
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ethers } from 'ethers';
|
|
7
|
+
import { ml_dsa65 } from '@noble/post-quantum/ml-dsa';
|
|
8
|
+
import { derivePQCAddress, deriveHybridAddress } from './utils/address.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* ECDSA Wallet (standard Ethereum wallet)
|
|
12
|
+
*/
|
|
13
|
+
export class ECDSAWallet {
|
|
14
|
+
constructor(privateKey, provider = null) {
|
|
15
|
+
this.wallet = new ethers.Wallet(privateKey, provider);
|
|
16
|
+
this.address = this.wallet.address;
|
|
17
|
+
this.privateKey = privateKey;
|
|
18
|
+
this.provider = provider;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Connect wallet to a provider
|
|
23
|
+
* @param {QuorumProvider} provider - Provider instance
|
|
24
|
+
* @returns {ECDSAWallet} New wallet instance connected to provider
|
|
25
|
+
*/
|
|
26
|
+
connect(provider) {
|
|
27
|
+
return new ECDSAWallet(this.privateKey, provider);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get public key
|
|
32
|
+
* @returns {string} Public key (hex)
|
|
33
|
+
*/
|
|
34
|
+
getPublicKey() {
|
|
35
|
+
return this.wallet.publicKey;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Sign a message
|
|
40
|
+
* @param {string|Uint8Array} message - Message to sign
|
|
41
|
+
* @returns {Promise<string>} Signature
|
|
42
|
+
*/
|
|
43
|
+
async signMessage(message) {
|
|
44
|
+
return await this.wallet.signMessage(message);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* PQC Wallet (Dilithium/ML-DSA-65)
|
|
50
|
+
*/
|
|
51
|
+
export class PQCWallet {
|
|
52
|
+
constructor(secretKey = null, publicKey = null) {
|
|
53
|
+
if (secretKey && publicKey) {
|
|
54
|
+
this.secretKey = secretKey instanceof Uint8Array ? secretKey : new Uint8Array(secretKey);
|
|
55
|
+
this.publicKey = publicKey instanceof Uint8Array ? publicKey : new Uint8Array(publicKey);
|
|
56
|
+
} else {
|
|
57
|
+
// Generate new key pair
|
|
58
|
+
const keyPair = ml_dsa65.keygen();
|
|
59
|
+
this.secretKey = keyPair.secretKey;
|
|
60
|
+
this.publicKey = keyPair.publicKey;
|
|
61
|
+
}
|
|
62
|
+
this.address = derivePQCAddress(this.publicKey);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create wallet from secret key
|
|
67
|
+
* Note: In practice, you would derive the public key from the secret key.
|
|
68
|
+
* This is a placeholder - full implementation would use key derivation.
|
|
69
|
+
* @param {Uint8Array|string} secretKey - Secret key
|
|
70
|
+
* @param {Uint8Array|string} publicKey - Public key (required if secretKey provided)
|
|
71
|
+
* @returns {PQCWallet} Wallet instance
|
|
72
|
+
*/
|
|
73
|
+
static fromSecretKey(secretKey, publicKey) {
|
|
74
|
+
if (!secretKey || !publicKey) {
|
|
75
|
+
throw new Error('Both secretKey and publicKey are required');
|
|
76
|
+
}
|
|
77
|
+
const secret = secretKey instanceof Uint8Array ? secretKey : ethers.getBytes(secretKey);
|
|
78
|
+
const pub = publicKey instanceof Uint8Array ? publicKey : ethers.getBytes(publicKey);
|
|
79
|
+
return new PQCWallet(secret, pub);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Sign a message hash
|
|
84
|
+
* @param {Uint8Array} hash - Message hash (32 bytes)
|
|
85
|
+
* @returns {Uint8Array} Signature
|
|
86
|
+
*/
|
|
87
|
+
sign(hash) {
|
|
88
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
89
|
+
return ml_dsa65.sign(this.secretKey, hash, ctx);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Verify a signature
|
|
94
|
+
* @param {Uint8Array} hash - Message hash
|
|
95
|
+
* @param {Uint8Array} signature - Signature to verify
|
|
96
|
+
* @returns {boolean} True if signature is valid
|
|
97
|
+
*/
|
|
98
|
+
verify(hash, signature) {
|
|
99
|
+
const ctx = new TextEncoder().encode('ML-DSA-65');
|
|
100
|
+
return ml_dsa65.verify(this.publicKey, hash, signature, ctx);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Get public key as hex string
|
|
105
|
+
* @returns {string} Public key (hex)
|
|
106
|
+
*/
|
|
107
|
+
getPublicKeyHex() {
|
|
108
|
+
return ethers.hexlify(this.publicKey);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get secret key as hex string (use with caution!)
|
|
113
|
+
* @returns {string} Secret key (hex)
|
|
114
|
+
*/
|
|
115
|
+
getSecretKeyHex() {
|
|
116
|
+
return ethers.hexlify(this.secretKey);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Hybrid Wallet (ECDSA + PQC)
|
|
122
|
+
*/
|
|
123
|
+
export class HybridWallet {
|
|
124
|
+
constructor(ecdsaWallet, pqcWallet) {
|
|
125
|
+
if (!ecdsaWallet || !pqcWallet) {
|
|
126
|
+
throw new Error('Both ECDSA and PQC wallets are required for Hybrid wallet');
|
|
127
|
+
}
|
|
128
|
+
this.ecdsaWallet = ecdsaWallet instanceof ECDSAWallet ? ecdsaWallet : new ECDSAWallet(ecdsaWallet);
|
|
129
|
+
this.pqcWallet = pqcWallet instanceof PQCWallet ? pqcWallet : new PQCWallet();
|
|
130
|
+
this.address = deriveHybridAddress(
|
|
131
|
+
ethers.getBytes(this.ecdsaWallet.getPublicKey()),
|
|
132
|
+
this.pqcWallet.publicKey
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Create hybrid wallet from ECDSA private key and PQC key pair
|
|
138
|
+
* @param {string} ecdsaPrivateKey - ECDSA private key (hex)
|
|
139
|
+
* @param {Uint8Array} pqcSecretKey - PQC secret key
|
|
140
|
+
* @param {Uint8Array} pqcPublicKey - PQC public key
|
|
141
|
+
* @returns {HybridWallet} Hybrid wallet instance
|
|
142
|
+
*/
|
|
143
|
+
static fromKeys(ecdsaPrivateKey, pqcSecretKey, pqcPublicKey) {
|
|
144
|
+
const ecdsaWallet = new ECDSAWallet(ecdsaPrivateKey);
|
|
145
|
+
const pqcWallet = new PQCWallet(pqcSecretKey, pqcPublicKey);
|
|
146
|
+
return new HybridWallet(ecdsaWallet, pqcWallet);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Connect wallet to a provider
|
|
151
|
+
* @param {QuorumProvider} provider - Provider instance
|
|
152
|
+
* @returns {HybridWallet} New wallet instance connected to provider
|
|
153
|
+
*/
|
|
154
|
+
connect(provider) {
|
|
155
|
+
const connectedECDSA = this.ecdsaWallet.connect(provider);
|
|
156
|
+
return new HybridWallet(connectedECDSA, this.pqcWallet);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-Knowledge Proof Transaction Support
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ethers } from 'ethers';
|
|
6
|
+
import { TX_TYPE, ZK_PROOF_SYSTEM } from './constants.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ZK Transaction Builder
|
|
10
|
+
* Creates transactions with zero-knowledge proofs
|
|
11
|
+
*/
|
|
12
|
+
export class ZKTransaction {
|
|
13
|
+
constructor(params) {
|
|
14
|
+
this.type = TX_TYPE.ZK_PRIVATE;
|
|
15
|
+
this.chainId = params.chainId || 1337;
|
|
16
|
+
this.nonce = params.nonce || 0;
|
|
17
|
+
this.gasPrice = params.gasPrice || 0n;
|
|
18
|
+
this.gasLimit = params.gasLimit || 21000n;
|
|
19
|
+
this.to = params.to;
|
|
20
|
+
this.value = params.value || 0n;
|
|
21
|
+
this.data = params.data || '0x';
|
|
22
|
+
this.accessList = params.accessList || [];
|
|
23
|
+
|
|
24
|
+
// ZK-specific fields
|
|
25
|
+
this.zkProofSystem = params.zkProofSystem || ZK_PROOF_SYSTEM.GROTH16;
|
|
26
|
+
this.zkProof = params.zkProof || null;
|
|
27
|
+
this.zkPublicInputs = params.zkPublicInputs || [];
|
|
28
|
+
this.zkVerificationKeyHash = params.zkVerificationKeyHash || null;
|
|
29
|
+
this.encryptedPayload = params.encryptedPayload || null;
|
|
30
|
+
this.recipients = params.recipients || [];
|
|
31
|
+
|
|
32
|
+
// Private transaction fields (Quorum)
|
|
33
|
+
this.privateFrom = params.privateFrom || null;
|
|
34
|
+
this.privateFor = params.privateFor || null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Create ZK transaction arguments for RPC call
|
|
39
|
+
* @param {string} from - Sender address
|
|
40
|
+
* @returns {Object} ZK transaction arguments
|
|
41
|
+
*/
|
|
42
|
+
toZKTxArgs(from) {
|
|
43
|
+
if (!this.zkProof || !this.zkProofSystem) {
|
|
44
|
+
throw new Error('ZK proof and proof system are required');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const args = {
|
|
48
|
+
from: from,
|
|
49
|
+
zkProofSystem: this.zkProofSystem,
|
|
50
|
+
zkProof: this.zkProof,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
if (this.to) args.to = this.to;
|
|
54
|
+
if (this.value) args.value = ethers.toBeHex(this.value);
|
|
55
|
+
if (this.gasLimit) args.gas = ethers.toBeHex(this.gasLimit);
|
|
56
|
+
if (this.gasPrice) args.gasPrice = ethers.toBeHex(this.gasPrice);
|
|
57
|
+
if (this.data) args.data = this.data;
|
|
58
|
+
if (this.nonce) args.nonce = ethers.toBeHex(this.nonce);
|
|
59
|
+
if (this.chainId) args.chainId = ethers.toBeHex(this.chainId);
|
|
60
|
+
if (this.accessList && this.accessList.length > 0) args.accessList = this.accessList;
|
|
61
|
+
if (this.zkPublicInputs && this.zkPublicInputs.length > 0) {
|
|
62
|
+
args.zkPublicInputs = this.zkPublicInputs.map(pi =>
|
|
63
|
+
typeof pi === 'string' ? pi : ethers.hexlify(pi)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (this.zkVerificationKeyHash) {
|
|
67
|
+
args.zkVerificationKeyHash = typeof this.zkVerificationKeyHash === 'string'
|
|
68
|
+
? this.zkVerificationKeyHash
|
|
69
|
+
: ethers.hexlify(this.zkVerificationKeyHash);
|
|
70
|
+
}
|
|
71
|
+
if (this.encryptedPayload) {
|
|
72
|
+
args.encryptedPayload = typeof this.encryptedPayload === 'string'
|
|
73
|
+
? this.encryptedPayload
|
|
74
|
+
: ethers.hexlify(this.encryptedPayload);
|
|
75
|
+
}
|
|
76
|
+
if (this.recipients && this.recipients.length > 0) {
|
|
77
|
+
args.recipients = this.recipients;
|
|
78
|
+
}
|
|
79
|
+
if (this.privateFrom) args.privateFrom = this.privateFrom;
|
|
80
|
+
if (this.privateFor) args.privateFor = this.privateFor;
|
|
81
|
+
|
|
82
|
+
return args;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Send ZK transaction via RPC
|
|
87
|
+
* @param {QuorumProvider} provider - Provider instance
|
|
88
|
+
* @param {string} from - Sender address
|
|
89
|
+
* @returns {Promise<string>} Transaction hash
|
|
90
|
+
*/
|
|
91
|
+
async send(provider, from) {
|
|
92
|
+
const args = this.toZKTxArgs(from);
|
|
93
|
+
return await provider.send('quorum_sendZKTransaction', [args]);
|
|
94
|
+
}
|
|
95
|
+
}
|