@cheny56/node-client
v1.0.16
Published
Client library for Quorum blockchain with Post-Quantum Cryptography (PQC) and Zero-Knowledge Proof (ZK) support
Maintainers
Readme
@cheny56/node-client
Client library for Quorum blockchain with Post-Quantum Cryptography (PQC) and Zero-Knowledge Proof (ZK) support.
Features
- Post-Quantum Cryptography: Support for Dilithium (ML-DSA-65) signatures
- Hybrid Signatures: Combine ECDSA and PQC for enhanced security
- Zero-Knowledge Proofs: Support for ZK transactions (Groth16, PLONK, STARK)
- Transaction Types: Legacy, AccessList, and DynamicFee transactions
- ERC20 Token Support: Simplified interface for token transfers
- CommonJS First: Uses
require()syntax by default (JavaScript-friendly)
Installation
npm install @cheny56/node-clientDependencies
ethers@^5.7.2- Ethereum librarydilithium-crystals@^1.0.0- Post-quantum cryptography implementation
Quick Start
Using CommonJS (Default)
const { QuorumProvider, ECDSAWallet, PQCWallet, HybridWallet } = require('@cheny56/node-client');
// Connect to Quorum node
const provider = new QuorumProvider('http://localhost:8545');
// Create ECDSA wallet (synchronous)
const ecdsaWallet = new ECDSAWallet('0x...', provider);
// Create PQC wallet (async - keys are generated asynchronously)
const pqcWallet = new PQCWallet();
await pqcWallet._initPromise; // Wait for keys to be generated
// Or use the static factory method (recommended)
const pqcWallet2 = await PQCWallet.create();
// Create hybrid wallet
const hybridWallet = new HybridWallet(ecdsaWallet, pqcWallet);
const hybridAddress = await hybridWallet.getAddress();Using ES Modules (Optional)
import { QuorumProvider, ECDSAWallet, PQCWallet } from '@cheny56/node-client';
// Same usage as CommonJS
const provider = new QuorumProvider('http://localhost:8545');
const pqcWallet = await PQCWallet.create();Wallets
ECDSA Wallet
Standard Ethereum wallet using ECDSA signatures.
const { ECDSAWallet } = require('@cheny56/node-client');
// Create from private key
const wallet = new ECDSAWallet('0x...', provider);
// Get address
console.log(wallet.address);
// Sign message
const signature = await wallet.signMessage('Hello, World!');PQC Wallet
Post-quantum wallet using Dilithium signatures. Note: Key generation is asynchronous.
const { PQCWallet } = require('@cheny56/node-client');
// Method 1: Create and wait for initialization
const wallet = new PQCWallet();
await wallet._initPromise; // Keys are generated in the background
console.log(wallet.address); // Now available
// Method 2: Use static factory (recommended)
const wallet2 = await PQCWallet.create();
console.log(wallet2.address); // Immediately available
// Method 3: Create from existing keys
const wallet3 = PQCWallet.fromSecretKey(secretKey, publicKey);
// Sign message hash
const hash = new Uint8Array(32); // Your message hash
const signature = await wallet.sign(hash);
// Verify signature
const isValid = await wallet.verify(hash, signature);
// Get keys (async)
const publicKeyHex = await wallet.getPublicKeyHex();
const secretKeyHex = await wallet.getSecretKeyHex();Important Notes:
- PQC key generation uses
dilithium.keyPair()which is async - Keys are generated in the background when you create a new wallet
- Always await
_initPromiseor usePQCWallet.create()before accessing keys/address - The
dilithium-crystalspackage returns{ publicKey, privateKey }- the library mapsprivateKeytosecretKeyinternally
Hybrid Wallet
Combines ECDSA and PQC signatures for enhanced security.
const { HybridWallet, ECDSAWallet, PQCWallet } = require('@cheny56/node-client');
// Create from ECDSA and PQC wallets
const ecdsaWallet = new ECDSAWallet('0x...');
const pqcWallet = await PQCWallet.create();
const hybridWallet = new HybridWallet(ecdsaWallet, pqcWallet);
// Get hybrid address (async - waits for PQC keys)
const address = await hybridWallet.getAddress();
// Or use static factory
const hybridWallet2 = await HybridWallet.create('0x...'); // ECDSA private key
// Create from existing keys
const hybridWallet3 = HybridWallet.fromKeys(
ecdsaPrivateKey,
pqcSecretKey,
pqcPublicKey
);Transactions
Legacy Transactions (Type 0)
ECDSA Transaction
const { LegacyTransaction } = require('@cheny56/node-client');
const tx = new LegacyTransaction({
chainId: 1337,
nonce: 0,
gasPrice: ethers.utils.parseUnits('20', 'gwei'),
gasLimit: 21000,
to: '0x...',
value: ethers.utils.parseEther('1.0'),
});
const signedTx = await tx.sign(ecdsaWallet);
const txHash = await provider.sendRawTransaction(signedTx);PQC Transaction
const { PQCLegacyTransaction } = require('@cheny56/node-client');
const tx = new PQCLegacyTransaction({
chainId: 1337,
nonce: 0,
gasPrice: 0n, // 0 if node doesn't charge gas
gasLimit: 21000,
to: '0x...',
value: ethers.utils.parseEther('1.0'),
});
// Sign with PQC wallet (async)
await tx.sign(pqcWallet);
const serialized = tx.getHex();
const txHash = await provider.sendRawTransaction(serialized);Hybrid Transaction
const { HybridLegacyTransaction } = require('@cheny56/node-client');
const tx = new HybridLegacyTransaction({
chainId: 1337,
nonce: 0,
gasPrice: 0n,
gasLimit: 21000,
to: '0x...',
value: ethers.utils.parseEther('1.0'),
});
// Sign with both wallets (async)
await tx.sign(ecdsaWallet, pqcWallet);
const serialized = tx.getHex();
const txHash = await provider.sendRawTransaction(serialized);AccessList Transactions (Type 1)
const { PQCAccessListTransaction } = require('@cheny56/node-client');
const tx = new PQCAccessListTransaction({
chainId: 1337,
nonce: 0,
gasPrice: 0n,
gasLimit: 21000,
to: '0x...',
value: ethers.utils.parseEther('1.0'),
accessList: [],
});
await tx.sign(pqcWallet);
const serialized = tx.getHex();
const txHash = await provider.sendRawTransaction(serialized);DynamicFee Transactions (Type 2)
const { PQCDynamicFeeTransaction } = require('@cheny56/node-client');
const tx = new PQCDynamicFeeTransaction({
chainId: 1337,
nonce: 0,
maxPriorityFeePerGas: ethers.utils.parseUnits('2', 'gwei'),
maxFeePerGas: ethers.utils.parseUnits('20', 'gwei'),
gasLimit: 21000,
to: '0x...',
value: ethers.utils.parseEther('1.0'),
accessList: [],
});
await tx.sign(pqcWallet);
const serialized = tx.getHex();
const txHash = await provider.sendRawTransaction(serialized);ERC20 Tokens
Standard Transfer (ECDSA)
const { ERC20Token } = require('@cheny56/node-client');
const token = new ERC20Token(tokenAddress, provider, ecdsaWallet);
// Transfer tokens
const tx = await token.transfer(recipientAddress, amount, {
gasPrice: ethers.utils.parseUnits('20', 'gwei'),
gasLimit: 100000,
});PQC Token Transfer
const { ERC20Token } = require('@cheny56/node-client');
const token = new ERC20Token(tokenAddress, provider);
// Transfer using PQC wallet (async)
const txHash = await token.transferPQC(
pqcWallet,
provider,
recipientAddress,
amount,
{
chainId: 1337,
gasPrice: 0n,
gasLimit: 100000,
}
);Hybrid Token Transfer
const { ERC20Token } = require('@cheny56/node-client');
const token = new ERC20Token(tokenAddress, provider);
// Transfer using hybrid wallet (async)
const txHash = await token.transferHybrid(
hybridWallet,
provider,
recipientAddress,
amount,
{
chainId: 1337,
gasPrice: 0n,
gasLimit: 100000,
}
);Zero-Knowledge Proof Transactions
const { ZKTransaction, ZK_PROOF_SYSTEM } = require('@cheny56/node-client');
const zkTx = new ZKTransaction({
chainId: 1337,
nonce: 0,
gasPrice: 0n,
gasLimit: 21000,
to: '0x...',
value: ethers.utils.parseEther('1.0'),
zkProofSystem: ZK_PROOF_SYSTEM.GROTH16,
zkProof: proofBytes,
zkPublicInputs: publicInputs,
zkVerificationKeyHash: vkHash,
});
const txHash = await zkTx.send(provider, senderAddress);Provider
const { QuorumProvider } = require('@cheny56/node-client');
const provider = new QuorumProvider('http://localhost:8545');
// Get block number
const blockNumber = await provider.getBlockNumber();
// Get balance
const balance = await provider.getBalance(address);
// Get transaction count (nonce)
const nonce = await provider.getTransactionCount(address);
// Send raw transaction
const txHash = await provider.sendRawTransaction(signedTxHex);
// Wait for transaction
const receipt = await provider.waitForTransaction(txHash);Constants
const {
TX_TYPE,
PQC_TYPE,
ZK_PROOF_SYSTEM,
DEFAULT_CHAIN_ID,
} = require('@cheny56/node-client');
// Transaction types
TX_TYPE.LEGACY // 0
TX_TYPE.ACCESS_LIST // 1
TX_TYPE.DYNAMIC_FEE // 2
TX_TYPE.ZK_PRIVATE // 4
// PQC types
PQC_TYPE.NONE // 0
PQC_TYPE.DILITHIUM // 1
// ZK proof systems
ZK_PROOF_SYSTEM.GROTH16 // 1
ZK_PROOF_SYSTEM.PLONK // 2
ZK_PROOF_SYSTEM.STARK // 3
// Default chain ID
DEFAULT_CHAIN_ID // 1337Utilities
const {
derivePQCAddress,
deriveHybridAddress,
isValidAddress,
encodeUint64,
encodeBigInt,
encodeSignature,
} = require('@cheny56/node-client');
// Derive PQC address from public key
const address = derivePQCAddress(publicKey);
// Derive hybrid address from ECDSA + PQC public keys
const hybridAddress = deriveHybridAddress(ecdsaPublicKey, pqcPublicKey);
// Validate address
const isValid = isValidAddress('0x...');
// RLP encoding utilities
const nonceHex = encodeUint64(5);
const valueHex = encodeBigInt(ethers.utils.parseEther('1.0'));
const sigHex = encodeSignature('0x...');Complete Example
const { QuorumProvider, PQCWallet, PQCLegacyTransaction } = require('@cheny56/node-client');
const { ethers } = require('ethers');
async function main() {
// Connect to node
const provider = new QuorumProvider('http://localhost:8545');
// Create PQC wallet (async)
const wallet = await PQCWallet.create();
console.log('PQC Address:', wallet.address);
// Get nonce
const nonce = await provider.getTransactionCount(wallet.address, 'pending');
// Create transaction
const tx = new PQCLegacyTransaction({
chainId: 1337,
nonce: nonce,
gasPrice: 0n, // 0 if node doesn't charge gas
gasLimit: 21000,
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
value: ethers.utils.parseEther('0.1'),
});
// Sign transaction (async)
await tx.sign(wallet);
const serialized = tx.getHex();
// Send transaction
const txHash = await provider.sendRawTransaction(serialized);
console.log('Transaction hash:', txHash);
// Wait for confirmation
const receipt = await provider.waitForTransaction(txHash);
console.log('Transaction confirmed in block:', receipt.blockNumber);
}
main().catch(console.error);API Reference
PQCWallet
Constructor
new PQCWallet(secretKey?, publicKey?)secretKey(optional): Existing secret key (Uint8Array or hex string)publicKey(optional): Existing public key (Uint8Array or hex string)- If both are omitted, keys are generated asynchronously
Static Methods
PQCWallet.create(): ReturnsPromise<PQCWallet>- Creates wallet with initialized keysPQCWallet.fromSecretKey(secretKey, publicKey): Creates wallet from existing keys
Instance Methods
async sign(hash: Uint8Array): Sign a message hashasync verify(hash: Uint8Array, signature: Uint8Array): Verify a signatureasync getAddress(): Get wallet address (waits for initialization if needed)async getPublicKeyHex(): Get public key as hex stringasync getSecretKeyHex(): Get secret key as hex string
Properties
secretKey: Uint8Array (null until initialized)publicKey: Uint8Array (null until initialized)address: string (null until initialized)_initialized: boolean_initPromise: Promise - Wait for this to ensure keys are generated
Notes
- CommonJS Default: This library uses CommonJS (
require) by default for JavaScript compatibility - Async Key Generation: PQC keys are generated asynchronously - always await initialization before use
- Gas Fees: Set
gasPriceto0nif your Quorum node doesn't charge gas fees - RLP Encoding: The library uses custom RLP encoding compatible with Go's RLP implementation
- Dilithium Package: Uses
dilithium-crystalspackage which returns{ publicKey, privateKey }fromkeyPair()
License
LGPL-3.0
