npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cheny56/zk-voting-native

v1.0.0

Published

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

Downloads

107

Readme

@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?

| Feature | snarkjs (Solidity) | Native (Precompile) | |---------|-------------------|---------------------| | Verification Gas | ~5,000,000 | ~200,000 | | Proof Gen Speed | ~2-5 seconds | ~200ms | | Trusted Setup | Required | Pre-deployed | | Hash Function | Poseidon | MiMC | | Best For | Any EVM chain | PQC-Quorum |

Prerequisites

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

Smart Contracts

Contract Overview

| Contract | Address | Description | |----------|---------|-------------| | VoterRegistry | Deployed | Merkle tree of eligible voters | | ZKBallot | Deployed | Main voting with precompile verification | | TallyManager | Deployed | Tallying orchestration | | IZKPrecompile | 0x16 | Native 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)

| Operation | Time | Gas | |-----------|------|-----| | Proof Generation | ~200ms | - | | On-chain Verification | - | ~200,000 | | Vote Registration | ~50ms | ~45,000 | | Full Vote Cast | ~300ms | ~250,000 |

Comparison

| Metric | Native (gnark) | snarkjs | |--------|---------------|---------| | Proof Gen | 200ms | 2-5s | | Verify Gas | 200k | 5M+ | | Setup | Pre-deployed | Custom |

Comparison

When to use which package?

| Use Case | Recommended 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 System | Circom/snarkjs | gnark/Groth16 | | Hash Function | Poseidon | MiMC | | Verification | Solidity | Precompile (0x16) | | Proof Generation | JavaScript | Go | | EVM Compatibility | Any | PQC-Quorum | | Gas Cost | ~5M | ~200k | | Trusted Setup | Custom | Pre-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

Related Packages