{"_id":"@cheny56/zk-voting-native","name":"@cheny56/zk-voting-native","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@cheny56/zk-voting-native","version":"1.0.0","description":"ZK Voting with Native PQC-Quorum Integration - Optimized for Groth16 precompile at 0x16","main":"client/index.js","types":"client/index.d.ts","scripts":{"example":"node scripts/example-native.js","example:basic":"node examples/basic-usage.js","example:merkle":"node examples/merkle-tree.js","example:homomorphic":"node examples/homomorphic.js","benchmark":"node scripts/benchmark.js","setup":"node scripts/setup-circuit.js","test":"node --test","lint":"eslint .","compile-go":"cd go && go build -o ../bin/zk-prover ."},"keywords":["zk","zero-knowledge","voting","groth16","gnark","pqc-quorum","ethereum","privacy","mimc","merkle-tree","precompile","homomorphic","paillier","anonymous"],"author":{"name":"PQC-Quorum Team"},"license":"MIT","dependencies":{"ethers":"^6.9.0","paillier-bigint":"^3.4.0"},"devDependencies":{"eslint":"^8.56.0"},"engines":{"node":">=18.0.0"},"repository":{"type":"git","url":"git+https://github.com/pqc-quorum/zk-voting-native.git"},"homepage":"https://github.com/pqc-quorum/zk-voting-native#readme","bugs":{"url":"https://github.com/pqc-quorum/zk-voting-native/issues"},"exports":{".":{"types":"./client/index.d.ts","default":"./client/index.js"},"./lib":{"types":"./lib/index.d.ts","default":"./lib/index.js"},"./contracts":"./contracts/"},"directories":{"doc":"docs","example":"examples","lib":"lib"},"_id":"@cheny56/zk-voting-native@1.0.0","gitHead":"655a03a933643bcc8ed8dd60a56592ecb397a815","_nodeVersion":"22.21.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-KUMKSoOAnRaQLtfR4QO3O29Dz4Eb+SCwoAjfNGo4mO3WBZCkEJ3sv6vQztcAdqi14KGzvOk5sLO9ObToRNZklw==","shasum":"e3d81f0a75e5a84e237ff30921fd120805dbf1d3","tarball":"https://registry.npmjs.org/@cheny56/zk-voting-native/-/zk-voting-native-1.0.0.tgz","fileCount":25,"unpackedSize":156805,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIFLjVgu9qEY8zBKOgSJkB4xJMnUumkrhDaOXuDsvjwIGAiA0IRBvYpTiG3JsVpK241ZcKWvYSZ1x9WFJaJm6H6rP3A=="}]},"_npmUser":{"name":"cheny56","email":"cheny5dyh@gmail.com"},"maintainers":[{"name":"cheny56","email":"cheny5dyh@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/zk-voting-native_1.0.0_1768973377703_0.49507985279686406"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-21T05:29:37.597Z","1.0.0":"2026-01-21T05:29:37.994Z","modified":"2026-01-21T05:29:38.181Z"},"maintainers":[{"name":"cheny56","email":"cheny5dyh@gmail.com"}],"description":"ZK Voting with Native PQC-Quorum Integration - Optimized for Groth16 precompile at 0x16","homepage":"https://github.com/pqc-quorum/zk-voting-native#readme","keywords":["zk","zero-knowledge","voting","groth16","gnark","pqc-quorum","ethereum","privacy","mimc","merkle-tree","precompile","homomorphic","paillier","anonymous"],"repository":{"type":"git","url":"git+https://github.com/pqc-quorum/zk-voting-native.git"},"author":{"name":"PQC-Quorum Team"},"bugs":{"url":"https://github.com/pqc-quorum/zk-voting-native/issues"},"license":"MIT","readme":"# @pqc-quorum/zk-voting-native\n\nZero-Knowledge Voting with Native PQC-Quorum Integration. Optimized for the Groth16 precompile at address `0x16`.\n\n[![npm version](https://img.shields.io/npm/v/@pqc-quorum/zk-voting-native.svg)](https://www.npmjs.com/package/@pqc-quorum/zk-voting-native)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## Features\n\n- 🚀 **Native Precompile Integration** - Uses Groth16 verifier at `0x16`\n- ⚡ **Gas-Efficient** - Precompile verification costs ~200k gas vs ~5M for Solidity\n- 🔧 **Go Prover** - `gnark`-based proof generation\n- 🔒 **MiMC Hash** - Compatible with gnark circuits\n- 📦 **Modular Design** - Separate lib for circuits, tallying, and client\n\n## Installation\n\n```bash\nnpm install @pqc-quorum/zk-voting-native\n```\n\n### Go Prover (Required for proof generation)\n\n```bash\n# Build the Go prover\ncd go && go build -o ../bin/zk-prover .\n```\n\n## Quick Start\n\n```javascript\nconst { VotingClient, ProofGenerator } = require('@pqc-quorum/zk-voting-native');\n\n// Connect to PQC-Quorum node\nconst client = new VotingClient('http://localhost:8545', privateKey);\n\n// Cast a vote with native ZK proof\nawait client.castVote(voterSecret, leafIndex, voteChoice);\n```\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Architecture](#architecture)\n- [Prerequisites](#prerequisites)\n- [Smart Contracts](#smart-contracts)\n- [Go Prover](#go-prover)\n- [JavaScript Client](#javascript-client)\n- [API Reference](#api-reference)\n- [Examples](#examples)\n- [Benchmarks](#benchmarks)\n- [Comparison with @pqc/zk-voting](#comparison)\n\n## Overview\n\nThis package provides a ZK voting system optimized for PQC-Quorum nodes with native Groth16 verification:\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                         NATIVE ZK VOTING FLOW                                │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│  ┌────────────────┐     ┌────────────────┐     ┌────────────────────────┐   │\n│  │ JavaScript     │     │ Go Prover      │     │ PQC-Quorum Node        │   │\n│  │ Client         │     │ (gnark)        │     │                        │   │\n│  └───────┬────────┘     └───────┬────────┘     └───────────┬────────────┘   │\n│          │                      │                          │                 │\n│          │  1. Prepare inputs   │                          │                 │\n│          ├─────────────────────>│                          │                 │\n│          │                      │ 2. Generate proof        │                 │\n│          │                      │    (gnark Groth16)       │                 │\n│          │<─────────────────────┤                          │                 │\n│          │  3. Proof bytes      │                          │                 │\n│          │                      │                          │                 │\n│          │  4. Submit tx ──────────────────────────────────>│                │\n│          │                      │                          │                 │\n│          │                      │    5. Verify via 0x16 ──>│                │\n│          │                      │                          │ (Precompile)   │\n│          │<─────────────────────────────────────────────────│                │\n│          │  6. Vote recorded    │                          │                 │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n### Why Native Integration?\n\n| Feature | snarkjs (Solidity) | Native (Precompile) |\n|---------|-------------------|---------------------|\n| **Verification Gas** | ~5,000,000 | ~200,000 |\n| **Proof Gen Speed** | ~2-5 seconds | ~200ms |\n| **Trusted Setup** | Required | Pre-deployed |\n| **Hash Function** | Poseidon | MiMC |\n| **Best For** | Any EVM chain | PQC-Quorum |\n\n## Prerequisites\n\n- **Node.js** >= 18.0.0\n- **Go** >= 1.21 (for proof generation)\n- **PQC-Quorum node** with ZK precompiles enabled\n\n## Smart Contracts\n\n### Contract Overview\n\n| Contract | Address | Description |\n|----------|---------|-------------|\n| **VoterRegistry** | Deployed | Merkle tree of eligible voters |\n| **ZKBallot** | Deployed | Main voting with precompile verification |\n| **TallyManager** | Deployed | Tallying orchestration |\n| **IZKPrecompile** | `0x16` | Native Groth16 verifier |\n\n### VoterRegistry.sol\n\n```solidity\n// Register voters (admin only)\nfunction registerVoter(bytes32 commitment) external;\nfunction registerVotersBatch(bytes32[] calldata commitments) external;\nfunction closeRegistration() external;\n\n// Query state\nfunction merkleRoot() external view returns (bytes32);\nfunction getVoterCount() external view returns (uint256);\n```\n\n### ZKBallot.sol\n\n```solidity\n// Cast vote with native ZK verification\nfunction castVote(\n    bytes calldata proof,           // Groth16 proof bytes\n    bytes calldata publicInputs,    // [merkleRoot, nullifier, commitment, count]\n    bytes[] calldata encryptedVote  // For homomorphic tally (optional)\n) external;\n\n// End voting\nfunction endVoting() external;\n\n// Query\nfunction getTotalVotes() external view returns (uint256);\nfunction nullifierUsed(bytes32) external view returns (bool);\n```\n\n### Native ZK Precompile\n\nThe precompile at `0x16` provides efficient Groth16 verification:\n\n```solidity\ninterface IZKPrecompile {\n    function verifyGroth16(\n        bytes32 vkHash,        // Hash of verification key\n        bytes calldata proof,   // 8 G1/G2 elements (256 bytes)\n        bytes calldata inputs   // Public inputs (32 bytes each)\n    ) external view returns (bool);\n}\n```\n\n## Go Prover\n\nThe Go prover uses `gnark` for Groth16 proof generation.\n\n### Circuit Definition\n\n```go\n// go/circuit/vote_circuit.go\ntype VoteCircuit struct {\n    // Private inputs\n    VoterSecret    frontend.Variable\n    VoterLeafIndex frontend.Variable\n    MerklePath     [20]frontend.Variable\n    PathIndices    [20]frontend.Variable\n    VoteChoice     frontend.Variable\n    VoteSalt       frontend.Variable\n\n    // Public inputs\n    MerkleRoot     frontend.Variable `gnark:\",public\"`\n    Nullifier      frontend.Variable `gnark:\",public\"`\n    VoteCommitment frontend.Variable `gnark:\",public\"`\n    CandidateCount frontend.Variable `gnark:\",public\"`\n}\n```\n\n### Building the Prover\n\n```bash\ncd go\ngo mod tidy\ngo build -o ../bin/zk-prover .\n```\n\n### Using the Prover\n\n```bash\n# Generate proof\n./bin/zk-prover prove \\\n    --secret 0x1234... \\\n    --leaf-index 5 \\\n    --merkle-path 0xabc...,0xdef...,... \\\n    --path-indices 0,1,0,... \\\n    --vote-choice 2 \\\n    --vote-salt 0x5678... \\\n    --merkle-root 0x9abc... \\\n    --candidate-count 4\n\n# Outputs: proof.bin, public_inputs.json\n```\n\n## JavaScript Client\n\n### VotingClient\n\nHigh-level client for the complete voting flow:\n\n```javascript\nconst { VotingClient } = require('@pqc-quorum/zk-voting-native');\n\nconst client = new VotingClient('http://localhost:8545', privateKey);\n\n// Deploy contracts\nawait client.deployVoterRegistry();\nawait client.deployZKBallot(candidates, duration, vkHash);\nawait client.deployTallyManager();\n\n// Admin: Register voters\nawait client.registerVoters([commitment1, commitment2, ...]);\nawait client.closeRegistration();\n\n// Voter: Cast vote\nawait client.castVote({\n    voterSecret: BigInt('0x...'),\n    leafIndex: 5,\n    voteChoice: 2,\n    candidateCount: 4,\n});\n\n// Query state\nconst totalVotes = await client.getTotalVotes();\nconst candidates = await client.getCandidates();\n```\n\n### ProofGenerator\n\nJavaScript wrapper for the Go prover:\n\n```javascript\nconst { ProofGenerator } = require('@pqc-quorum/zk-voting-native');\n\nconst prover = new ProofGenerator({\n    proverPath: './bin/zk-prover',\n    circuitPath: './circuits/vote.r1cs',\n    pkPath: './keys/proving.key',\n});\n\n// Generate proof\nconst { proof, publicInputs } = await prover.generateProof({\n    voterSecret,\n    leafIndex,\n    merklePath,\n    pathIndices,\n    voteChoice,\n    voteSalt,\n    merkleRoot,\n    candidateCount,\n});\n```\n\n## API Reference\n\n### VotingClient\n\n```javascript\nclass VotingClient {\n    constructor(rpcUrl: string, privateKey: string);\n    \n    // Deployment\n    deployVoterRegistry(): Promise<Contract>;\n    deployZKBallot(\n        candidates: string[],\n        durationSeconds: number,\n        vkHash: string\n    ): Promise<Contract>;\n    deployTallyManager(): Promise<Contract>;\n    \n    // Connect to existing\n    connectVoterRegistry(address: string): void;\n    connectZKBallot(address: string): void;\n    connectTallyManager(address: string): void;\n    \n    // Admin functions\n    registerVoter(commitment: string): Promise<TransactionReceipt>;\n    registerVoters(commitments: string[]): Promise<TransactionReceipt>;\n    closeRegistration(): Promise<TransactionReceipt>;\n    \n    // Voting\n    castVote(params: CastVoteParams): Promise<{\n        nullifier: string;\n        voteCommitment: string;\n        txHash: string;\n    }>;\n    \n    // Queries\n    getMerkleRoot(): Promise<string>;\n    getTotalVotes(): Promise<bigint>;\n    getCandidates(): Promise<Candidate[]>;\n    isNullifierUsed(nullifier: string): Promise<boolean>;\n    getVoteCommitments(): Promise<string[]>;\n    \n    // Tallying\n    endVoting(): Promise<TransactionReceipt>;\n    submitHomomorphicTally(tally: number[]): Promise<TransactionReceipt>;\n}\n\ninterface CastVoteParams {\n    voterSecret: bigint;\n    leafIndex: number;\n    voteChoice: number;\n    candidateCount: number;\n}\n```\n\n### Lib Exports\n\n```javascript\nconst {\n    // Crypto\n    mimcHash,\n    bigIntToHex32,\n    hex32ToBigInt,\n    \n    // Merkle Tree\n    MerkleTree,\n    \n    // Vote Proof\n    generateVoteProofInputs,\n    TREE_DEPTH,\n    \n    // Tally\n    RevealTally,\n    HomomorphicTally,\n    PaillierCrypto,\n} = require('@pqc-quorum/zk-voting-native/lib');\n```\n\n### MerkleTree\n\n```javascript\nconst { MerkleTree, mimcHash } = require('@pqc-quorum/zk-voting-native/lib');\n\n// Create tree\nconst tree = new MerkleTree(20); // depth 20\n\n// Add leaves\nawait tree.addLeaf(commitment1);\nawait tree.addLeaf(commitment2);\n\n// Get root\nconst root = tree.getRoot();\n\n// Generate proof\nconst { pathElements, pathIndices } = await tree.generateProof(commitment, index);\n```\n\n## Examples\n\n### Complete Voting Flow\n\n```javascript\nconst {\n    VotingClient,\n    ProofGenerator,\n    MerkleTree,\n    mimcHash,\n    bigIntToHex32,\n} = require('@pqc-quorum/zk-voting-native');\n\nasync function completeVotingExample() {\n    // Setup\n    const rpcUrl = 'http://localhost:8545';\n    const adminKey = process.env.ADMIN_PRIVATE_KEY;\n    const candidates = ['Alice', 'Bob', 'Charlie'];\n    \n    // Initialize client\n    const client = new VotingClient(rpcUrl, adminKey);\n    \n    // Deploy contracts\n    console.log('Deploying contracts...');\n    await client.deployVoterRegistry();\n    await client.deployZKBallot(candidates, 3600, VK_HASH);\n    await client.deployTallyManager();\n    \n    // Register voters\n    const voters = [];\n    const tree = new MerkleTree(20);\n    \n    for (let i = 0; i < 10; i++) {\n        const secret = BigInt(crypto.randomBytes(32).toString('hex'), 16);\n        const commitment = await mimcHash(secret);\n        voters.push({ secret, commitment, index: i });\n        await tree.addLeaf(commitment);\n    }\n    \n    const commitments = voters.map(v => bigIntToHex32(v.commitment));\n    await client.registerVoters(commitments);\n    await client.closeRegistration();\n    \n    console.log(`Registered ${voters.length} voters`);\n    console.log(`Merkle root: ${bigIntToHex32(tree.getRoot())}`);\n    \n    // Cast votes\n    for (const voter of voters) {\n        const voteChoice = Math.floor(Math.random() * candidates.length);\n        \n        const result = await client.castVote({\n            voterSecret: voter.secret,\n            leafIndex: voter.index,\n            voteChoice,\n            candidateCount: candidates.length,\n        });\n        \n        console.log(`Vote cast: ${result.txHash}`);\n    }\n    \n    // End voting and get results\n    await client.endVoting();\n    const totalVotes = await client.getTotalVotes();\n    console.log(`Total votes: ${totalVotes}`);\n}\n```\n\n### Local Testing with Mock Prover\n\n```javascript\nconst { VotingClient, MockProofGenerator } = require('@pqc-quorum/zk-voting-native');\n\n// Use mock prover for testing (no Go required)\nconst client = new VotingClient(rpcUrl, privateKey, {\n    proofGenerator: new MockProofGenerator(),\n});\n```\n\n## Benchmarks\n\nRun benchmarks with:\n\n```bash\nnpm run benchmark\n```\n\n### Results (PQC-Quorum Testnet)\n\n| Operation | Time | Gas |\n|-----------|------|-----|\n| **Proof Generation** | ~200ms | - |\n| **On-chain Verification** | - | ~200,000 |\n| **Vote Registration** | ~50ms | ~45,000 |\n| **Full Vote Cast** | ~300ms | ~250,000 |\n\n### Comparison\n\n| Metric | Native (gnark) | snarkjs |\n|--------|---------------|---------|\n| Proof Gen | 200ms | 2-5s |\n| Verify Gas | 200k | 5M+ |\n| Setup | Pre-deployed | Custom |\n\n## Comparison\n\n### When to use which package?\n\n| Use Case | Recommended Package |\n|----------|---------------------|\n| **PQC-Quorum node** | `@pqc-quorum/zk-voting-native` |\n| **Any EVM chain** | `@pqc/zk-voting` |\n| **Maximum portability** | `@pqc/zk-voting` |\n| **Maximum performance** | `@pqc-quorum/zk-voting-native` |\n| **No Go environment** | `@pqc/zk-voting` |\n\n### Feature Matrix\n\n| Feature | @pqc/zk-voting | @pqc-quorum/zk-voting-native |\n|---------|---------------|-------------------------------|\n| **ZK System** | Circom/snarkjs | gnark/Groth16 |\n| **Hash Function** | Poseidon | MiMC |\n| **Verification** | Solidity | Precompile (0x16) |\n| **Proof Generation** | JavaScript | Go |\n| **EVM Compatibility** | Any | PQC-Quorum |\n| **Gas Cost** | ~5M | ~200k |\n| **Trusted Setup** | Custom | Pre-deployed |\n| **Homomorphic Tally** | ✓ | ✓ |\n| **Reveal-Based Tally** | ✓ | ✓ |\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Build Go prover\nnpm run compile-go\n\n# Run example\nnpm run example\n\n# Run benchmarks\nnpm run benchmark\n```\n\n## License\n\nMIT\n\n## Related Packages\n\n- [@pqc/zk-voting](../zk-voting) - Portable ZK voting with snarkjs\n- [@pqc-quorum/zk-client](../zk-client) - ZK RPC client for PQC-Quorum nodes\n","readmeFilename":"README.md","_rev":"1-e61f3707b549d50b0708eb221e3bb06a"}