New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@cheny56/zk-voting-native

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cheny56/zk-voting-native

ZK Voting with Native PQC-Quorum Integration - Optimized for Groth16 precompile at 0x16

latest
Source
npmnpm
Version
1.0.0
Version published
Maintainers
1
Created
Source

@pqc-quorum/zk-voting-native

Zero-Knowledge Voting with Native PQC-Quorum Integration. Optimized for the Groth16 precompile at address 0x16.

npm version License: MIT

Features

  • 🚀 Native Precompile Integration - Uses Groth16 verifier at 0x16
  • Gas-Efficient - Precompile verification costs ~200k gas vs ~5M for Solidity
  • 🔧 Go Prover - gnark-based proof generation
  • 🔒 MiMC Hash - Compatible with gnark circuits
  • 📦 Modular Design - Separate lib for circuits, tallying, and client

Installation

npm install @pqc-quorum/zk-voting-native

Go Prover (Required for proof generation)

# Build the Go prover
cd go && go build -o ../bin/zk-prover .

Quick Start

const { VotingClient, ProofGenerator } = require('@pqc-quorum/zk-voting-native');

// Connect to PQC-Quorum node
const client = new VotingClient('http://localhost:8545', privateKey);

// Cast a vote with native ZK proof
await client.castVote(voterSecret, leafIndex, voteChoice);

Table of Contents

Overview

This package provides a ZK voting system optimized for PQC-Quorum nodes with native Groth16 verification:

┌─────────────────────────────────────────────────────────────────────────────┐
│                         NATIVE ZK VOTING FLOW                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌────────────────┐     ┌────────────────┐     ┌────────────────────────┐   │
│  │ JavaScript     │     │ Go Prover      │     │ PQC-Quorum Node        │   │
│  │ Client         │     │ (gnark)        │     │                        │   │
│  └───────┬────────┘     └───────┬────────┘     └───────────┬────────────┘   │
│          │                      │                          │                 │
│          │  1. Prepare inputs   │                          │                 │
│          ├─────────────────────>│                          │                 │
│          │                      │ 2. Generate proof        │                 │
│          │                      │    (gnark Groth16)       │                 │
│          │<─────────────────────┤                          │                 │
│          │  3. Proof bytes      │                          │                 │
│          │                      │                          │                 │
│          │  4. Submit tx ──────────────────────────────────>│                │
│          │                      │                          │                 │
│          │                      │    5. Verify via 0x16 ──>│                │
│          │                      │                          │ (Precompile)   │
│          │<─────────────────────────────────────────────────│                │
│          │  6. Vote recorded    │                          │                 │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Why Native Integration?

Featuresnarkjs (Solidity)Native (Precompile)
Verification Gas~5,000,000~200,000
Proof Gen Speed~2-5 seconds~200ms
Trusted SetupRequiredPre-deployed
Hash FunctionPoseidonMiMC
Best ForAny EVM chainPQC-Quorum

Prerequisites

  • Node.js >= 18.0.0
  • Go >= 1.21 (for proof generation)
  • PQC-Quorum node with ZK precompiles enabled

Smart Contracts

Contract Overview

ContractAddressDescription
VoterRegistryDeployedMerkle tree of eligible voters
ZKBallotDeployedMain voting with precompile verification
TallyManagerDeployedTallying orchestration
IZKPrecompile0x16Native Groth16 verifier

VoterRegistry.sol

// Register voters (admin only)
function registerVoter(bytes32 commitment) external;
function registerVotersBatch(bytes32[] calldata commitments) external;
function closeRegistration() external;

// Query state
function merkleRoot() external view returns (bytes32);
function getVoterCount() external view returns (uint256);

ZKBallot.sol

// Cast vote with native ZK verification
function castVote(
    bytes calldata proof,           // Groth16 proof bytes
    bytes calldata publicInputs,    // [merkleRoot, nullifier, commitment, count]
    bytes[] calldata encryptedVote  // For homomorphic tally (optional)
) external;

// End voting
function endVoting() external;

// Query
function getTotalVotes() external view returns (uint256);
function nullifierUsed(bytes32) external view returns (bool);

Native ZK Precompile

The precompile at 0x16 provides efficient Groth16 verification:

interface IZKPrecompile {
    function verifyGroth16(
        bytes32 vkHash,        // Hash of verification key
        bytes calldata proof,   // 8 G1/G2 elements (256 bytes)
        bytes calldata inputs   // Public inputs (32 bytes each)
    ) external view returns (bool);
}

Go Prover

The Go prover uses gnark for Groth16 proof generation.

Circuit Definition

// go/circuit/vote_circuit.go
type VoteCircuit struct {
    // Private inputs
    VoterSecret    frontend.Variable
    VoterLeafIndex frontend.Variable
    MerklePath     [20]frontend.Variable
    PathIndices    [20]frontend.Variable
    VoteChoice     frontend.Variable
    VoteSalt       frontend.Variable

    // Public inputs
    MerkleRoot     frontend.Variable `gnark:",public"`
    Nullifier      frontend.Variable `gnark:",public"`
    VoteCommitment frontend.Variable `gnark:",public"`
    CandidateCount frontend.Variable `gnark:",public"`
}

Building the Prover

cd go
go mod tidy
go build -o ../bin/zk-prover .

Using the Prover

# Generate proof
./bin/zk-prover prove \
    --secret 0x1234... \
    --leaf-index 5 \
    --merkle-path 0xabc...,0xdef...,... \
    --path-indices 0,1,0,... \
    --vote-choice 2 \
    --vote-salt 0x5678... \
    --merkle-root 0x9abc... \
    --candidate-count 4

# Outputs: proof.bin, public_inputs.json

JavaScript Client

VotingClient

High-level client for the complete voting flow:

const { VotingClient } = require('@pqc-quorum/zk-voting-native');

const client = new VotingClient('http://localhost:8545', privateKey);

// Deploy contracts
await client.deployVoterRegistry();
await client.deployZKBallot(candidates, duration, vkHash);
await client.deployTallyManager();

// Admin: Register voters
await client.registerVoters([commitment1, commitment2, ...]);
await client.closeRegistration();

// Voter: Cast vote
await client.castVote({
    voterSecret: BigInt('0x...'),
    leafIndex: 5,
    voteChoice: 2,
    candidateCount: 4,
});

// Query state
const totalVotes = await client.getTotalVotes();
const candidates = await client.getCandidates();

ProofGenerator

JavaScript wrapper for the Go prover:

const { ProofGenerator } = require('@pqc-quorum/zk-voting-native');

const prover = new ProofGenerator({
    proverPath: './bin/zk-prover',
    circuitPath: './circuits/vote.r1cs',
    pkPath: './keys/proving.key',
});

// Generate proof
const { proof, publicInputs } = await prover.generateProof({
    voterSecret,
    leafIndex,
    merklePath,
    pathIndices,
    voteChoice,
    voteSalt,
    merkleRoot,
    candidateCount,
});

API Reference

VotingClient

class VotingClient {
    constructor(rpcUrl: string, privateKey: string);
    
    // Deployment
    deployVoterRegistry(): Promise<Contract>;
    deployZKBallot(
        candidates: string[],
        durationSeconds: number,
        vkHash: string
    ): Promise<Contract>;
    deployTallyManager(): Promise<Contract>;
    
    // Connect to existing
    connectVoterRegistry(address: string): void;
    connectZKBallot(address: string): void;
    connectTallyManager(address: string): void;
    
    // Admin functions
    registerVoter(commitment: string): Promise<TransactionReceipt>;
    registerVoters(commitments: string[]): Promise<TransactionReceipt>;
    closeRegistration(): Promise<TransactionReceipt>;
    
    // Voting
    castVote(params: CastVoteParams): Promise<{
        nullifier: string;
        voteCommitment: string;
        txHash: string;
    }>;
    
    // Queries
    getMerkleRoot(): Promise<string>;
    getTotalVotes(): Promise<bigint>;
    getCandidates(): Promise<Candidate[]>;
    isNullifierUsed(nullifier: string): Promise<boolean>;
    getVoteCommitments(): Promise<string[]>;
    
    // Tallying
    endVoting(): Promise<TransactionReceipt>;
    submitHomomorphicTally(tally: number[]): Promise<TransactionReceipt>;
}

interface CastVoteParams {
    voterSecret: bigint;
    leafIndex: number;
    voteChoice: number;
    candidateCount: number;
}

Lib Exports

const {
    // Crypto
    mimcHash,
    bigIntToHex32,
    hex32ToBigInt,
    
    // Merkle Tree
    MerkleTree,
    
    // Vote Proof
    generateVoteProofInputs,
    TREE_DEPTH,
    
    // Tally
    RevealTally,
    HomomorphicTally,
    PaillierCrypto,
} = require('@pqc-quorum/zk-voting-native/lib');

MerkleTree

const { MerkleTree, mimcHash } = require('@pqc-quorum/zk-voting-native/lib');

// Create tree
const tree = new MerkleTree(20); // depth 20

// Add leaves
await tree.addLeaf(commitment1);
await tree.addLeaf(commitment2);

// Get root
const root = tree.getRoot();

// Generate proof
const { pathElements, pathIndices } = await tree.generateProof(commitment, index);

Examples

Complete Voting Flow

const {
    VotingClient,
    ProofGenerator,
    MerkleTree,
    mimcHash,
    bigIntToHex32,
} = require('@pqc-quorum/zk-voting-native');

async function completeVotingExample() {
    // Setup
    const rpcUrl = 'http://localhost:8545';
    const adminKey = process.env.ADMIN_PRIVATE_KEY;
    const candidates = ['Alice', 'Bob', 'Charlie'];
    
    // Initialize client
    const client = new VotingClient(rpcUrl, adminKey);
    
    // Deploy contracts
    console.log('Deploying contracts...');
    await client.deployVoterRegistry();
    await client.deployZKBallot(candidates, 3600, VK_HASH);
    await client.deployTallyManager();
    
    // Register voters
    const voters = [];
    const tree = new MerkleTree(20);
    
    for (let i = 0; i < 10; i++) {
        const secret = BigInt(crypto.randomBytes(32).toString('hex'), 16);
        const commitment = await mimcHash(secret);
        voters.push({ secret, commitment, index: i });
        await tree.addLeaf(commitment);
    }
    
    const commitments = voters.map(v => bigIntToHex32(v.commitment));
    await client.registerVoters(commitments);
    await client.closeRegistration();
    
    console.log(`Registered ${voters.length} voters`);
    console.log(`Merkle root: ${bigIntToHex32(tree.getRoot())}`);
    
    // Cast votes
    for (const voter of voters) {
        const voteChoice = Math.floor(Math.random() * candidates.length);
        
        const result = await client.castVote({
            voterSecret: voter.secret,
            leafIndex: voter.index,
            voteChoice,
            candidateCount: candidates.length,
        });
        
        console.log(`Vote cast: ${result.txHash}`);
    }
    
    // End voting and get results
    await client.endVoting();
    const totalVotes = await client.getTotalVotes();
    console.log(`Total votes: ${totalVotes}`);
}

Local Testing with Mock Prover

const { VotingClient, MockProofGenerator } = require('@pqc-quorum/zk-voting-native');

// Use mock prover for testing (no Go required)
const client = new VotingClient(rpcUrl, privateKey, {
    proofGenerator: new MockProofGenerator(),
});

Benchmarks

Run benchmarks with:

npm run benchmark

Results (PQC-Quorum Testnet)

OperationTimeGas
Proof Generation~200ms-
On-chain Verification-~200,000
Vote Registration~50ms~45,000
Full Vote Cast~300ms~250,000

Comparison

MetricNative (gnark)snarkjs
Proof Gen200ms2-5s
Verify Gas200k5M+
SetupPre-deployedCustom

Comparison

When to use which package?

Use CaseRecommended Package
PQC-Quorum node@pqc-quorum/zk-voting-native
Any EVM chain@pqc/zk-voting
Maximum portability@pqc/zk-voting
Maximum performance@pqc-quorum/zk-voting-native
No Go environment@pqc/zk-voting

Feature Matrix

Feature@pqc/zk-voting@pqc-quorum/zk-voting-native
ZK SystemCircom/snarkjsgnark/Groth16
Hash FunctionPoseidonMiMC
VerificationSolidityPrecompile (0x16)
Proof GenerationJavaScriptGo
EVM CompatibilityAnyPQC-Quorum
Gas Cost~5M~200k
Trusted SetupCustomPre-deployed
Homomorphic Tally
Reveal-Based Tally

Development

# Install dependencies
npm install

# Build Go prover
npm run compile-go

# Run example
npm run example

# Run benchmarks
npm run benchmark

License

MIT

Keywords

zk

FAQs

Package last updated on 21 Jan 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts