The Coinholder Voting Chain

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.

  1. (Off-chain) Question feedback: The vote coordinator multisig is expected to require public review of questions for at least 5 days to collect feedback.

  2. 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.

  3. 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.

  4. 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.

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!

8 Likes

Thanks for sharing. Here is what grok thinks, because I was curious and since we are moving so fast:

Undiscussed or under-discussed trade-offs

Complexity and attack surface. The new design adds PIR servers, submission servers, multi-stage ZKPs, VAN lifecycle, DKG, and threshold decryption proofs. Each is a new place for implementation bugs, side-channels, DoS, or misconfiguration. Previous system reused far more of the existing Orchard circuit surface and had a simpler ballot model. More components = more things that must be correct simultaneously.

PIR dependency. Clients rely on PIR servers for private non-membership proofs against the nullifier set. If those servers are operated by the same parties as the validators, collude, or become unavailable, privacy or liveness fails. PIR has its own cryptographic and availability assumptions that are not equivalent to “just download the tree.” Mobile bandwidth/latency and long-term maintenance of the PIR service are real operational costs that grow with the nullifier set.

Hotkey / VAN model. Authority is transferred to a governance hotkey that owns the VAN. Compromise of that key after the snapshot (or a malicious wallet that generates it) lets an attacker cast the vote. Previous system stayed closer to the spend authority of the original notes. The hotkey is a new trust/UX surface.

Fixed 16-way split. This is a concrete privacy vs cost knob. More shares improve resistance to reconstruction and timing analysis; fewer reduce proof/submission overhead. The number is currently hard-coded. There is little public discussion of adaptive splitting, cost under high participation, or whether 16 is sufficient against a sophisticated colluding set + traffic analysis.

Coordinator power. The 2-of-5 cannot alter or censor individual votes, but it controls which questions appear, the round parameters, and the encryption key attestation. Agenda-setting centralization remains. “Anyone can run their own chain” is true but does not solve social consensus around the official tally.

Liveness and threshold decryption. Tally requires ≥2/3 of the validator set to produce correct partial decryptions at the end. Refusal, outage, or coordinated delay stalls the result. The previous seed-reveal model had simpler (if more centralized) finalization.

Residual privacy under full collusion. The design correctly notes that even a fully colluding MPC committee + quantum computer cannot easily re-attribute full amounts because of the split + delayed independent submissions. However, advanced timing/network analysis against the submission servers, or correlation across multiple proposals, is not eliminated. This residual risk is more subtle than the all-or-nothing decryption of the older system.

Audit status and maturity. Coin Voting 2.0 had a public Least Authority audit with concrete findings that drove the BFT upgrade. The new system has a Zellic audit of the PIR component and strong design claims, but a full-stack audit of the circuits, DKG, submission path, and wallet integration path is less visible in the public record at the time of the design post. Shipping for a high-stakes vote (1M ZEC threshold) under time pressure increases the cost of any remaining soundness or implementation gap.

Hardware wallet and UI risks. Both systems work around Keystone’s limited verification of nullifiers and transaction semantics. The new “fake 1-zat note” signing path still depends on the wallet UI clearly distinguishing a voting action from a real spend. Phishing or confused-deputy risks are not zero.

Participation and concentration. Lower friction should raise turnout, which is good. It does not change the power-law distribution of holdings. Previous votes were heavily whale-dominated; the new system inherits the same underlying capital concentration.

Security and privacy bottom line

The new design improves on the most painful previous weaknesses (fund movement, nullifier leakage, single-authority withholding, and weak amount privacy under collusion). It does so by adding cryptographic layers (PIR, share splitting, homomorphic + threshold decryption with proofs) that are independently verifiable in principle.

The cost is higher systemic complexity, new trusted (or semi-trusted) services (PIR + submission servers), a hotkey authority model, and residual risks that are harder to reason about than the older, simpler failure modes. The coordinator multisig and the social reliance on the official validator set remain points of governance centralization even if cryptographic vote integrity holds.

For a production coinholder vote the critical questions are whether the full stack has been audited to the same depth as Coin Voting 2.0, whether PIR and submission servers have clear independent operators and SLAs, and whether wallets surface the VAN/hotkey and multi-share flow without introducing new user-error or phishing vectors. Those operational and audit details matter at least as much as the elegant cryptographic improvements.

1 Like

This reply is, as you-noted, LLM-regurgitated hesitance on defense in depths?

If you compare any of this to the existing system, you see almost all of these points as hardening, which if broken, reduce you to today’s weaker guarantee.

  • PIR: Ok great, don’t use PIR, just have your phone download 2GB for Orchard votes, or ~10MB for Ironwood votes. This PIR is audited. “Real long-term maintenance costs” does not hold up here, can you quantify the concern.
  • Hotkey / VAN model: This doesn’t hold up. You realize the current system requires you to put your mnemonic into a new application, that is far more dangerous!
  • Fixed 16-way split: This protects you against a threat model, the current voting doesn’t even care about. The current voting leaks every single voter’s vote amount. So you have to manually split this. We definitely should make this dynamic to allow more splits in the future, but this is far stronger than the current system!
  • Coordinator power: This is already true?
  • Liveness and threshold decryption: Yes, I argue this is clearly a good trade-off for privacy of user’s balances. The prior model being ok is crazy to me.
  • Residual privacy under full collusion: That agrees with this is better :), I would love to keep layering in defense in depths to reduce the risk of all user balances revealed.
  • Audit status and maturity: This has a circuit audit by Sean Bowe, and audits of the chain code. Only PIR has a potential privacy relevant leakage. None of these imply risk to privacy. This was done in the past as well, any coinholder is welcome to consider it insecure
  • Hardware wallet and UI risks.: No the old system does not work around it, you just can’t do it. The new system has a worst case risk to the user of losing less than $0.0001 if malicious software wallet AND they had a real 1 zat note (impossible). But this transaction cannot land, because it can’t even pay the tx fee.
  • Participation and concentration: Yup should greatly improve voter turnout :slight_smile:

PIR services are explicitly not trusted, and importantly does not matter if they are the same as the share submission servers. The new system has live dashboards, and block explorers so you can track uptime. The old system would have multi-day downtime mid-vote.

By default, the share submission servers are the same as the validators, but more folks can operate these.

In the future, I ask that you do not LLM regurgitate output for questions, and refine them yourself. :slight_smile:

2 Likes

I love that I have access to grok to help me, and potentially the community, to better understand these cleary very complex setups. Thank you for also clarifying the mistakes and stating your perspectives. I will continue to use AI tools as I see fit. :smiling_face_with_three_hearts:

3 Likes

@ValarDragon I’m trying to run a validator on a Debian 13 LXC container and I faced some issues…

  1. The installed systemd service set a fixed PATH and so the wrapper can’t find basic commands such as sleep and awk.
  2. The hashbang in wrapper causes an error env: ‘bash’: Not a directory but I have env and bash in the right places.

I resolved both issues changing the systemd service…

...
Environment="SVOTE_PATH=/etc/systemd/system/svoted.service" ...
ExecStart=/usr/bin/env bash -c 'export PATH=$PATH:$SVOTE_PATH && exec /home/svote/.local/bin/svoted-wrapper.sh'
...

I have also a question: the service binds on localhost only? Can I change it to 0.0.0.0? I need to expose it via tailscale with a caddy proxy from the exit node.

EDIT: for now I’m using a caddy service on lxc container that proxys unencrypted traffic from tailnet ip to localhost. I managed to expose on tailnet the service listening on localhost using tailscale serve.

EDIT2: PR opened!

EDIT3: probably you will see a couple of pending approvals from me, consider the latest one only

Thanks!

1 Like

Your validator is up and added! Would you be able to message me your Signal by chance so I can add you to a channel for organizing upgrades and such? I don’t think there is a DM feature here so you can email it to me at adam@valargroup.dev

1 Like