This post includes details of the voting chain, being used in the latest NU7 coin holder vote , and intended for the pre-security incident vote.
The high level of the voting chain:
- A voting round includes a “snapshot height”, an “end time” and multiple “proposals”.
- 1 Ironwood ZEC at snapshot height = 1 vote. (Transparent voters are handled as done today)
- Wallets configured to a given chain will automatically read all published voting rounds. (Wallets may choose to require additional approvals to display votes)
- Voters privately snapshot their balance from the Zcash mainnet, proving it to the voting chain. The voting chain actions are unlinkable to their Zcash notes.
- Voters vote on each proposal, with the amount homomorphically encrypted to an MPC committee.
- When the voting round ends, votes are homomorphically tallied. The MPC committee members submit partial decryptions with proofs of correctness. These decryptions are combined, as is the proof of correctness. All permissionless full nodes auditably validate the final decryption.
Governance of the voting chain
-
A coordinator multisig: coordinates vote round creation and validator admission. It authorizes which questions reach the chain and attests to each round’s encryption key. The current design proposes a 2-of-5 multisig with representatives from Project Tachyon, Zcash Foundation, Zodl, Shielded Labs, and Valar Group. This parameter is easily adjustable later based on community feedback.
-
An election authority. It consists of vote chain validators: at least 10 nodes run the chain and hold the per-round decryption key shares. The validators run the distributed key generation (DKG) ceremony to produce the key and perform the threshold decryption when a round closes. No single validator can decrypt a ballot. The only decryption produced in cleartext is the final tally. The threshold is 2/3rds of the validators, rounding up.
Neither membership is hard-coded into the protocol. The coordinator set and the validator set are both configurations of the chain and can be updated outside of an ongoing vote. We’d really love to see it be easier to call votes over time.
Authorizing proposals to vote on
Everything in this section occurs before a single vote is cast.
-
(Off-chain) Question feedback: The vote coordinator multisig is expected to require public review of questions for at least 5 days to collect feedback.
-
Question authorization and Snapshot: Once the wording is final, one coordinator member enters the questions, an end date, and snapshot height into the coordinator UI (or a self-hosted instance). Other vote coordinator members ratify the questions, snapshot height, and end date until the multisig threshold is met. Once the threshold quorum is reached, the questions and relevant Zcash mainnet data are written to the vote chain. This is the only stage where the coordinator exercises judgment over content, and we can iterate towards more accessible methods in the future.
-
Threshold key generation. Upon round creation, the validators automatically run an in-protocol distributed key generation (DKG). The output is a round-specific threshold encryption key that voters encrypt their amounts to. The corresponding decryption key is distributed across validators and is never directly assembled.
-
Coordinator signing the threshold key. A coordinator then signs that public key off-chain. This signature is downloaded by wallets and checked when they download the encryption key for this round to prevent supply-chain-related attacks.
Voting process
The key design requirements are:
-
1 Ironwood ZEC at snapshot height = 1 Vote
-
Unlinkability: Your vote cannot be linked to your on-chain note. (No knowledge of your on-chain nullifier leaks)
-
Amount privacy: The amount of ZEC you hold is private knowledge, and is kept private via multi-layered security assumptions. (MPC encrypted amounts, splitting votes into 16 chunks, delaying submission of split votes to prevent timing linkage)
-
Publicly verifiable: Anyone can validate every vote and audit that the tally was done correctly.
A round runs in three proof steps. For each, a wallet constructs the proof and executes a vote chain transaction. Successful proof verification triggers the next step.
Snapshot ZKP exists to break the link between voter identity and the wallet used to vote, while following today’s Keystone constraints (only signing mainnet Ironwood transactions).
This is achieved by proving an unspent balance at snapshot height, and creating a new “voting authority note” (VAN) with that balance on the voting chain. This note is owned by a governance hotkey that the wallet generates on your behalf. As in standard Zcash, no one ever sees this note value. The wallet signs over a fake 1 zatoshi note, and ZK proves necessary statements. With hardware wallet upgrades in the future, this ZKP could be combined into the vote ZKP, and have the vote choice be auditable in Keystone.
Vote Commitment ZKP is run per-proposal. The voter decides on their vote choice for a given proposal, and their wallet software will pseudo-randomly split their vote amount into 16 encrypted shares (read more here). This consumes their current VAN, and outputs a vote commitment (VC) of their shares to the vote choice and a new VAN that no longer has authority to vote on this proposal. The encrypted vote shares are then submitted separately, severing the link between each other. The wallet submits shares to multiple submission servers, which further eliminates the timing link between shares. These servers act as long-running producers of Reveal ZKPs. See ”Submission servers” below for details.
In a future upgrade, we plan to enable dynamically splitting to more than 16 encrypted shares.
Reveal ZKP is produced once per vote-share. It proves that the encrypted vote share came from a valid vote commitment. Once the proof is submitted to the vote chain, the encrypted amount is homomorphically accumulated for the corresponding vote choice.
In-protocol tally. At the end of the vote, the validators provide partial decryptions of the tally with proofs of correctness. Once the threshold is reached, the tally becomes available for anyone to view with a combined correctness proof.
Nullifier exclusion proofs with Private Information Retrieval
A detail of the Snapshot ZKP is that users must prove that their note was unspent at the snapshot height. In mainnet Zcash, this is done by revealing your nullifier, and all full nodes check for uniqueness. This does not work for voting, due to requiring unlinkability.
Instead, we achieve this by creating a sorted Merkle tree of all used nullifiers at the snapshot height. The wallet ZK-proves knowledge of a Merkle path showing that its nullifier was not used at the height. However, wallets cannot directly query a server for their nullifier’s Merkle path, because that would leak the nullifier. In Orchard, the full data set is 2GB and is impractical for mobile clients to download. If we 100x the usage of Zcash, this would quickly become 100+ GB.
Private Information Retrieval (PIR) enables users to privately query servers for this Merkle path, with low bandwidth usage. This will continue to work, even at 100x Zcash’s scale. The client succinctly retrieves the proof material it needs while cryptographically hiding the nullifier. The exclusion proof is checked against the published nullifier-set root, so a malicious or buggy server can’t fabricate a valid-looking non-membership. Zellic audited the implemented scheme, and the scheme is described here.
Submission servers
The submission servers exist to help hide information about the user’s balance, even in the event of silent MPC committee collusion, where they silently decrypt the amount encryptions. They also protect against a quantum computer, which yields the same capability.
The user’s balance is split across 16 shares. However, that alone is insufficient, since if you submitted 16 shares on-chain at the same time, it’s clear that all shares came from the same person. So instead, the wallet assigns a random submission time for each share and sends each share to multiple distinct “submission servers”. Each submission server will submit the vote share on behalf of the user at the specified time, and multiple servers (but not all) are sent for redundancy and censorship resistance.
Every validator on the vote chain is configured to run a submission server.
These layers (DKG, submission servers, and share splitting) complement each other to maximize privacy for the user’s balance. We acknowledge that these protections are lowered in the case of collusion, but still layer in security measures to mitigate risk.
Trust model
| Column 1 | Column 2 | Column 3 | Column 4 |
|---|---|---|---|
| Property | Who could threaten it | Worst case if that party is malicious or colludes | Independently verifiable |
| Vote ↔ mainnet identity unlinkability | No one | A round-scoped hotkey casts the ballot, and no mainnet transaction is produced. The Snapshot ZKP proves balance without revealing the notes. Nothing on the vote chain links a ballot to a mainnet note. | Yes. The chain verifies each delegation and voting proof |
| Amount privacy (below MPC threshold) | Validators / MPC committee | Decryption needs ≥ t validators. The system tolerates up to n − t malicious validators with no loss of amount privacy. No single validator holds the key. | Hidden even from validators. Only the final aggregate is ever decrypted |
| Amount privacy (silent MPC collusion, or Quantum computer) | A fully colluding MPC committee, or a Quantum computer | Even if the committee silently reconstructs the key and decrypts every share, it cannot recover any individual’s total. Each amount is split into 16 shares submitted separately, with the cross-share link and submission timing severed, so decrypted shares can’t be reattributed to a voter. A single submission server only ever sees a subset of a voter’s shares. | No. Voters do not submit the full amount to any validator to avoid revealing it if the MPC committee colludes. |
| Amount privacy (substituted encryption key) | A malicious RPC / config server | An attacker could try to feed wallets an incorrect encryption key to read amounts. However, the coordinator signs the round key, and the wallet verifies that signature. Ballots are only ever encrypted to a signed-over key. | Yes, the wallet checks the coordinator’s attestation |
| Which questions reach the chain | Coordinator multisig (2-of-5) | It chooses which questions are authorized, but cannot see, alter, or block individual votes; anyone can run their own chain and re-point. | Yes, authorizations are on-chain |
| Final tally | Validators | They cannot cryptographically fabricate a tally. | Yes, any full node can audit the decryption |
Run your own / audit this
The design is intended to be open and reusable: any group should be able to surface polls, any wallet should be able to display them, and anyone should be able to run a chain or audit a result.
- Voting chain code / how to run a validator: https://setup.valargroup.org
- Audit a published tally: https://tally.valargroup.org
- Run your own chain or stand up a self-hosted admin UI: GitHub - valargroup/vote-sdk: Application specific chain for private on-chain voting for Zcash holders · GitHub
- Run your own PIR server: https://setup-pir.valargroup.org
- Add your infrastructure to the recommended wallet config: GitHub - valargroup/token-holder-voting-config: Service discovery configuration for shielded voting. Staging and production server lists fetched by wallets via GitHub Pages CDN. · GitHub
- Documentation: Introduction | Valargroup Docs
- Code
- vote-sdk (chain): GitHub - valargroup/vote-sdk: Application specific chain for private on-chain voting for Zcash holders · GitHub
- voting-circuits: GitHub - valargroup/voting-circuits · GitHub
- vote-nullifier-pir: GitHub - valargroup/vote-nullifier-pir: Private Information Retrieval (PIR) system for Zcash nullifier non-membership proofs · GitHub
- zcash_voting (client): GitHub - valargroup/zcash_voting: Zcash shielded voting library — core protocol, proof generation, storage, and FFI bindings · GitHub
Thanks to everyone who has reviewed the design so far, the node operators participating in testing rounds, and the Vizor and Zodl teams for collaboration on the wallet integration. And all of Valar group who brought this system into reality!
