Skip to content

Latest commit

 

History

15 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Orkid Labs

zk-ballot

By Orkid Labs — privacy-first crypto engineering

Anonymous on-chain voting with Halo2 zero-knowledge proofs, scored by FMD physics energy.

Built for the Thrive zkVerify Web3 Program. Energy model adapted from the orkid FMD (Financial Molecular Dynamics) MEV detection engine.

Note: The orkid repository is private. Access can be provided to Thrive Protocol reviewers and other appropriate cases on request — contact Orkid Labs. The theoretical foundation is published as a preprint: "Negative EV per Unit Time as Blockchain Inefficiency"Jacob Cavazos, ResearchGate.


What it does

zk-ballot lets a group of registered voters cast secret ballots on-chain. Each voter produces a Halo2 zero-knowledge proof that proves:

  1. They are registered — their commitment is a leaf in a publicly-known Merkle tree (the voter registry)
  2. They haven't voted before — a nullifier hash is published that uniquely identifies them without revealing which leaf is theirs
  3. Their vote is valid — the vote is constrained to be boolean (0 or 1)
  4. The vote is bound to the proof — a vote commitment hash ties the ballot to this specific proof

No one — not the tally authority, not other voters, not the chain — can link a proof back to the voter who produced it.

Each proof is scored by its thermodynamic energy — the negentropy extracted from private data, adapted from the orkid FMD physics engine.

The thermodynamic framing

zk-ballot applies the Financial Molecular Dynamics (FMD) physics framework from the orkid MEV detection engine to score anonymous voting proofs. This is not metaphor — the mathematics of statistical mechanics, information theory, and zero-knowledge proofs are fundamentally connected.

Negentropy = Information = Order

From Brillouin's negentropy principle (1953) and the orkid blog post "Negentropy = Information: A Generalized Mathematical Framework":

Negentropy = H_max − H_actual = D_KL(p_informed || p_uninformed)

A vote is a high-entropy state — without proof, anyone could claim eligibility and cast arbitrary ballots. A ZK vote proof is a negentropy extraction: it converts private, chaotic data (voter identity + ballot) into structured, verifiable order (proof of eligible membership + valid vote) without revealing either.

Extracted vs. preserved entropy

The genius of ZK voting is that it extracts negentropy (verifiable order) while preserving entropy (privacy):

Before proof After proof
Voter identity High entropy (anyone could claim) Negentropy extracted: eligibility proven. Entropy preserved: identity hidden in anonymity set of 2^depth
Vote value High entropy (could be anything) Negentropy extracted: vote is boolean. Entropy preserved: actual vote hidden
Double-voting Uncertain Negentropy extracted: nullifier proves uniqueness

For the zk-ballot circuit (3,811 constraints, depth-4 tree):

N = constraint_count × tree_depth = 3,811 × 4 = 15,244 bits

This is the Shannon entropy reduction — the amount of uncertainty about voter eligibility eliminated by the proof. The tree depth determines the anonymity set size (2^depth = 16 voters), and the Poseidon hash chip contributes the bulk of the constraints per tree level.

Landauer's principle

From Landauer (1961) and the orkid blog post "Blockchain Thermodynamics: How Negentropy Explains MEV, Consensus, and Arbitrage":

E ≥ k_B × T × ln(2) per bit erased

Proof generation pays the thermodynamic cost of extracting negentropy. The compute energy spent generating the Halo2 proof is the Landauer cost of creating 15,244 bits of order from private chaos. The verifier receives this order without paying the cost.

The MEV closure analogy

From the orkid blog post "A Formal Mathematical Model of Blockchain Negentropy and MEV Dynamics":

dM/dt = a·δ + b·H_M − c·χ(I)·M

In MEV: information closes arbitrage opportunities. In zk-ballot: the ZK proof "closes" the uncertainty about voter eligibility. The proof is the information injection that collapses the entropy of the unverifiable ballot into a deterministic set of public assertions (registered, not double-voted, valid vote).

The energy model

The ballot energy model is adapted from the route energy formula in the orkid FMD physics engine (fmd-physics/src/route_energy.rs):

FMD route energy (orkid)

energy = net_bps × √(depth_ratio × timing_factor) × latency_decay × (1 − gas_penalty)

This scores arbitrage paths by net output, liquidity depth, timing, and gas cost. Higher energy = more profitable route.

Ballot energy (zk-ballot)

energy = confidence × √(depth_ratio × timing_factor) × latency_decay × (1 − cost_penalty)

This scores ZK vote proofs by registry confidence, anonymity strength, recency, proof speed, and verification cost. Higher energy = higher quality proof.

Factor FMD (MEV) zk-ballot (voting)
Confidence Pool TVL (liquidity depth) Registry trust score (credential strength)
Depth ratio Reserve ratio / trade size Confidence × tree_depth / 10
Timing factor 1/√(hops) exp(−age / half_life)
Latency decay (1 − 0.001 × hops × latency) 1 / (1 + total_latency × 0.0001)
Cost penalty Gas units × gas cost On-chain verification cost

Committor function

Adapted from the TPS (Transition Path Sampling) committor in the FMD engine, which predicts the probability of reaching a profitable state:

committor = (depth_ratio / (1 + depth_ratio)) × timing_factor × (1 − cost_penalty × 0.5)

This estimates the probability that the vote is valid and uncontested — a "rare event" prediction for ballot quality. A fresh proof from a trusted registry with a deep tree yields a committor near 1.0.

Example

For a 5-voter election (depth-4 tree, 16-voter anonymity set), registry trust=0.95, proof gen ~1s:

Metric Value
Energy per proof ~127
Negentropy per proof 15,244 bits
Committor 97.2%
Anonymity set 16 voters
Total negentropy (5 proofs) 76,220 bits
Proof size 5152 bytes

Public inputs

Index Name Purpose
0 merkle_root Anchors the proof to a specific voter registry
1 nullifier Prevents double-voting (unique per voter)
2 vote_commitment Binds the vote to this proof (for tally / reveal)

Private witnesses

Witness Purpose
secret Voter's private key (never revealed)
nullifier_seed Derives the nullifier (never revealed)
vote The actual ballot (0 = no, 1 = yes)
merkle_path[] Authentication path from leaf to root
position Leaf index in the tree

Circuit architecture

                    ┌─────────────────────────────────────────────┐
                    │              VoteCircuit                     │
                    │                                              │
  secret ──────┐   │  ┌──────────┐   ┌─────────────────────┐      │
  nullifier ───┼──▶│  │ HashChip │──▶│  leaf = H(s, n)     │      │
  seed ────────┘   │  └──────────┘   └────────┬────────────┘      │
                    │                          │                   │
                    │                ┌─────────▼──────────┐        │
                    │                │  MerkleChip         │        │
  merkle_path ─────▶│                │  (depth-4 tree)     │        │
  position ────────▶│                │  conditional swap   │        │
                    │                │  + hash per level   │        │
                    │                └─────────┬──────────┘        │
                    │                          │                   │
                    │          root ───────────▶ instance[0]       │
                    │                                              │
                    │  ┌──────────┐   ┌─────────────────────┐      │
                    │  │ HashChip │──▶│ nullifier = H(n, 0) │──▶instance[1]
                    │  └──────────┘   └─────────────────────┘      │
                    │                                              │
                    │  vote*(1-vote) = 0  ◀── boolean constraint   │
                    │                                              │
                    │  ┌──────────┐   ┌─────────────────────┐      │
                    │  │ HashChip │──▶│ commit = H(v, s)    │──▶instance[2]
                    │  └──────────┘   └─────────────────────┘      │
                    └─────────────────────────────────────────────┘

Chips

  • HashChip — production-standard Poseidon permutation over BN254 (t=3, x⁵ S-box, R_F=8 full + R_P=57 partial rounds, circulant MDS [[3,1,1],[1,3,1],[1,1,3]], fixed-column round constants). All 195 round constants are generated via rejection sampling to ensure they are valid, non-zero BN254 scalars. Forging requires inverting Poseidon over BN254.

  • MerkleChip — conditional-swap gate per tree level: enforces pos_bit booleanity, computes left/right via mux, then hashes the pair. This is the standard pattern used by Tornado Cash, Semaphore, and vocdoni.

Quick start

# Build
cargo build --release

# Run the end-to-end demo (5 voters, real Halo2 proofs + FMD energy scores)
cargo run --release --bin demo

Expected output

=== zk-ballot: Anonymous Voting with Halo2 ===

Tree depth: 4 (up to 16 voters)

Voter registry Merkle root: 0x...
Registered 5 voters

--- MockProver sanity check ---
  voter 0 mock proof verified ✓
  ...

--- Real Halo2 proof generation ---
Circuit parameter k = 12 (2^12 rows)
Setup SRS: ~60s
Keygen (vk + pk): ~14s

  voter 0 proof generated in ~35s (5152 bytes)
  voter 0 proof verified in ~900ms
    energy=~127  negentropy=15,244 bits  committor=97.2%  anonymity_set=16
  ...

=== Tally ===
YES: 3
NO:  2

=== FMD Physics Energy Summary ===
Model: FMD Route Energy (adapted from orkid fmd-physics/src/route_energy.rs)
Formula: energy = confidence * sqrt(depth_ratio * timing_factor) * latency_decay * (1 - cost_penalty)
Negentropy: N = constraint_count * tree_depth = 3,811 * 4 = 15,244 bits/proof
Total energy: ~623
Total negentropy extracted: 76,220 bits
Average energy per proof: ~125
Average negentropy per proof: 15,244 bits

Run tests

cargo test

Performance

Measured on Apple Silicon (M-series), k=12 (4096 rows):

Operation Time
SRS setup ~60s
Keygen (vk + pk) ~14s
Prove (per voter) ~35s
Verify (per proof) ~900ms
Proof size 5152 bytes
Energy per proof ~125
Negentropy per proof 15,244 bits

Tech stack

  • Halo2 (PSE fork, halo2_proofs 0.3) — PLONK-based ZK proving system with no trusted setup
  • halo2curves — BN254 curve arithmetic (EVM-compatible)
  • FMD physics energy model (adapted from orkid) — thermodynamic proof quality scoring
  • Rust — no external dependencies beyond the crypto stack

Why Halo2?

Halo2 uses the Inner Product Argument (IPA) commitment scheme, which requires no trusted setup ceremony — a critical advantage for decentralized governance.

Note on EVM compatibility: IPA-based Halo2 proofs on BN254 are not directly verifiable inside a Solidity contract. EVM on-chain verification requires the KZG commitment-scheme variant of Halo2, which in turn requires a trusted setup. The current implementation uses IPA; switching to KZG is on the roadmap if on-chain EVM verification becomes a hard requirement. For now, proofs are verified off-chain or via zkVerify.

Project structure

zk-ballot/
├── Cargo.toml
├── src/
│   ├── lib.rs              # Library exports
│   ├── circuit.rs          # VoteCircuit — ties together all constraints
│   ├── hash.rs             # HashChip — production-standard BN254 Poseidon permutation
│   ├── merkle.rs           # MerkleChip — conditional-swap membership proof
│   ├── tree.rs             # Off-circuit Merkle tree + helpers
│   ├── ballot_energy.rs    # FMD physics energy model (adapted from orkid)
│   └── bin/
│       └── demo.rs         # CLI demo — full voting session + energy scores
└── README.md

Thrive zkVerify Web3 Program (#45) — Grant Plan

Ecosystem value proposition

zk-ballot drives proof verification volume to zkVerify. Each anonymous vote generates a Halo2 ZK proof that is submitted to zkVerify for verification. The proof proves vote validity (eligible voter, single vote, correct tally) without revealing voter identity.

Scenario Votes/election Proofs to zkVerify/election
DAO governance (mid-size) 500 500
Community poll (large) 2,000 2,000
Multi-election (quarterly) 5,000 5,000
Annual (10 elections) ~20,000 ~20,000

25,000+ ZK Proofs (Milestone 2: Initial Traction target) is achievable with ~25,000 votes verified — well within a year of mid-size DAO governance.

Milestone roadmap

Progressive achievement over 150 days, following Thrive's zkVerify Web3 Program milestone structure.

Application Requirements (10% unlocked at approval):

  • ✅ Detailed technical plan showing how zero-knowledge proofs will be integrated and verified using zkVerify
  • ✅ Zero-knowledge focused user experience design
  • ✅ Token utility and ecosystem value proposition
  • ✅ Business plan demonstrating revenue model and sustainability beyond grant period

Milestone 1: Live Deployment (10% unlocked) — 45 days post approval:

  • Production deployment with fully functional zkVerify integration and proof verification
  • Beta testing with proof verification validation
  • Published documentation covering zkVerify integration and proof verification processes

Technical scope: Solidity verifier contract (on-chain proof verification), voter registry contract (manages Merkle root on-chain), tally contract (accumulates vote commitments, reveals tally), zkVerify proof submission pipeline. The Poseidon hash chip is already implemented and verified.

Milestone 2: Initial Traction (30% unlocked) — 90 days post approval:

  • Early traction metrics, choose one of the following:
    • Transaction Volume: 25,000+ ZK Proofs sent to zkVerify
    • Unique Users: 250+ unique addresses interacting with zkVerify integration

Milestone 3: Scale (50% unlocked) — 150 days post approval:

  • Choose one of the following:
    • Transaction Volume: 250,000+ ZK Proofs sent to zkVerify
    • Unique Users: 2,500+ unique addresses interacting with zkVerify integration

Why this matters for zkVerify

zkVerify provides dedicated, low-cost verification of zero-knowledge proofs on-chain. Anonymous voting generates high proof volume — every ballot is a separate Halo2 proof. By verifying these proofs on zkVerify, governance systems get cryptographic guarantees of vote validity without burdening the host chain's execution layer.

References

The FMD physics energy model is adapted from the orkid workspace (private repo — access available for reviewers on request). The theoretical foundation is published as a preprint: "Negative EV per Unit Time as Blockchain Inefficiency" by Jacob Cavazos.

  • Route energy formula: orkid/fmd-physics/src/route_energy.rs
  • TPS committor function: orkid/fmd-physics/src/tps.rs
  • Profit potential energy: orkid/fmd-physics/src/profit_potential.rs

Blog posts establishing the thermodynamic framework (publicly available at orkidlabs.com/blog):

About

Built by Orkid Labs — a privacy-first crypto engineering lab building thermodynamic infrastructure for decentralized systems. See our other work at orkidlabs.com.

License

MIT

About

Anonymous on-chain voting with Halo2 zero-knowledge proofs — Thrive/Horizen grant demo

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages