All posts
Why On-Chain Governance Needs Private Voting (And the Module We Built for It)
zeroknowledge-proofsweb3cryptocurrencydecentralizationblockchain

Why On-Chain Governance Needs Private Voting (And the Module We Built for It)

SachinMay 20, 2026Read on Medium

Every on-chain governance vote you have ever cast is public. Forever. Anyone can pull up your address, see how you voted on every proposal, correlate it with your delegations, your trading activity, your token movements. The whole point of secret ballots in democratic systems has been quietly abandoned by the chains that talk the loudest about decentralization.

This is not a theoretical problem. We have watched validators get pressured to vote a certain way because their stakers can see the vote. We have watched delegators move stake purely to retaliate against governance positions. We have watched whales coordinate openly because the on-chain record makes coordination trivial. None of this is governance. It is a coordination game with a permanent audit log.

Zero-knowledge proofs solve this. And we built the Cosmos module that brings ZK voting to any chain in the ecosystem.

What ZK Voting Actually Does

The core insight is simple. Voting needs two properties that pull in opposite directions. The vote tally must be verifiable, so anyone can check the outcome is correct. The individual vote must be private, so no one can link a specific vote to a specific person.

Cryptography has known how to do this for decades. The problem has always been making it practical on a blockchain.

The pattern looks like this. A voter who is eligible for a proposal first registers a commitment using their real address. The commitment is a cryptographic hash that locks in their vote choice without revealing it. Later, the voter generates a zero-knowledge proof that says, in effect: “I own one of the valid commitments registered for this proposal, and my vote is for option X.” The proof reveals nothing about which commitment is theirs.

That proof gets submitted from a different address, one that has no on-chain link to the voter’s real identity. The chain verifies the proof, counts the vote, and the tally is done.

You get a verifiable election and an unbreakable ballot in the same system.

Why Cosmos, and Why Now

ZK tooling has matured to the point where this is finally practical at protocol scale. Groth16 proofs are fast to verify on-chain. Circuit libraries have stabilized. The cryptographic primitives are no longer the bottleneck.

Cosmos in particular needs this. The Cosmos Hub, Osmosis, Neutron, Celestia, and every consumer chain running the standard x/gov module has the same governance privacy problem. Validator vote visibility is built into the design. There is no way to vote without your position being public.

The argument for transparency in governance was always that it prevents manipulation. In practice, public voting has produced the opposite outcome. Whales know what other whales are doing. Validators feel pressure from their stakers. Coordination is open, and dissent is expensive. Privacy in voting is not the enemy of accountability. It is the foundation of free participation.

cosmos-zk-gov is our answer. It is a Cosmos SDK module that adds ZK-based anonymous voting to any chain that wants to integrate it. The module ships as x/zkgov, exposes the standard create-proposal and vote flows, and handles all the proof generation and verification logic internally. It uses Groth16 for proof construction and a Merkle commitment scheme to accumulate registered voters into an anonymity set.

Where This Fits

A fair pushback on any ZK governance pitch is whether it actually makes Cosmos Hub votes anonymous, given that validators are publicly identifiable by design. The honest answer is that cosmos-zk-gov is not a drop-in replacement for x/gov. It is a separate x/zkgov module, built for governance flows where individual voter anonymity is the actual goal.

That covers a lot of ground. DAO-style chains, treasury votes, council elections, and any governance model where individual identity matters rather than validator-weighted stake gets a fully private ballot. It also works as a delegator-override layer alongside standard validator voting, so a delegator can dissent from their validator without exposing themselves on-chain.

What it does not try to do is hide validator behavior inside the existing Cosmos Hub flow. Validator addresses are tied to consensus, slashing, and delegator relationships. Anonymizing them would require rebuilding the staking model itself, which is a much larger redesign and not what this module ships today. cosmos-zk-gov is for chains and applications that want anonymity built in from the ground up, not for retrofitting privacy onto a system that depends on public validator identity.

The Dispatcher Problem

There is a subtle issue in any ZK voting system that most papers gloss over. Your proof says “I am one of the registered voters.” But the transaction carrying that proof has to be signed by some address, and that address has to pay gas. If you sign it with your real address, the anonymity is gone.

The naive answer is “use a different wallet.” But most users do not have a spare unlinkable address with gas in it. Asking them to set one up defeats the user experience.

We built a dispatcher service to solve this. The dispatcher is a small HTTP server that accepts a signed vote payload from any voter, signs the actual on-chain transaction with its own funded address, and broadcasts it. The dispatcher cannot tamper with the vote because the ZK proof binds the vote choice cryptographically. It cannot forge votes because it does not have access to the underlying commitments. It is a relay, not an authority.

Anyone can run a dispatcher. Multiple dispatchers can operate in parallel. A voter can choose which one to use or run their own. The trust assumption is minimal: the dispatcher might refuse to relay your vote, but it cannot change it or reveal your identity.

Here is the basic flow:

# Voter registers commitment from their real address
zkappd tx zk-gov register-vote [proposal-id] YES \
--from alice --keyring-backend test --chain-id zkapp
# Voter generates ZK proof and submits via dispatcher
zkappd tx zk-gov vote [proposal-id] [register-address] \
--dispatcher [dispatcher-address]

The dispatcher receives the proof, signs and broadcasts the on-chain transaction, and the vote is counted without ever linking the two addresses.

What Comes Next

We see cosmos-zk-gov as the start of a broader push to bring privacy primitives into Cosmos governance. The current implementation handles binary YES/NO votes on simple proposals. Future versions will support weighted voting, multi-option ballots, and delegation-aware voting where a delegator can override their validator’s vote anonymously.

There is also work to do on the Merkle tree side. Today, we generate multiple prover and verifier key pairs to accommodate different commitment set sizes. The next version targets a fixed-size Merkle tree of 2³¹ leaves with O(log n) updates, which removes that limitation entirely.

The repo is at github.com/vitwit/cosmos-zk-gov. It is MIT-licensed and open for contributions. If your chain runs the standard x/gov module and you want to give your voters real privacy, this is the module to integrate.

Public voting was a temporary state of the on-chain governance world. The cryptography to do better has existed for years. We are just shipping it.

Vitwit is a blockchain infrastructure company that has been building in the Cosmos ecosystem since 2017. We focus on validator infrastructure, developer tooling, and protocol-level contributions across multiple chains.


Why On-Chain Governance Needs Private Voting (And the Module We Built for It) was originally published in Vitwit on Medium, where people are continuing the conversation by highlighting and responding to this story.