Skip to content

[ZIP TBD] Shielded Voting Protocol#1200

Open
p0mvn wants to merge 58 commits into
zcash:mainfrom
valargroup:roman/voting-protocol
Open

[ZIP TBD] Shielded Voting Protocol#1200
p0mvn wants to merge 58 commits into
zcash:mainfrom
valargroup:roman/voting-protocol

Conversation

@p0mvn

@p0mvn p0mvn commented Mar 5, 2026

Copy link
Copy Markdown

Summary

This PR introduces Shielded Voting Protocol — a complete specification for stake-weighted governance voting over the Zcash Orchard shielded pool. Holders prove their ZEC balance via the Orchard Proof-of-Balance and cast votes without revealing their identity, individual balances, or vote allocations.

This is the core governance ZIP in the approved ZIP breakdown, building on two previously submitted ZIPs:

  • Orchard Balance Proof — the foundational primitive for proving note ownership without revealing standard nullifiers
  • Nullifier PIR — private retrieval of exclusion proofs used during delegation

Protocol at a glance

The protocol proceeds in five phases:

  1. Delegation — A holder proves ownership of unspent Orchard notes at a pool snapshot and delegates voting power to an unlinkable governance hotkey, producing a Vote Authority Note (VAN) on a purpose-built vote chain.
  2. Voting — The hotkey consumes a VAN and produces a Vote Commitment containing 16 El Gamal-encrypted shares of the voter's ballot count, split across vote options.
  3. Share submission — The voter sends each encrypted share to one or more untrusted submission servers.
  4. Share reveal — Each server constructs a Vote Reveal Proof (proving the share belongs to a valid VC without revealing which one) and submits it at a randomized delay.
  5. Tally — Validators holding Shamir shares of the election authority key cooperate to produce partial decryptions; results are combined via Lagrange interpolation and publicly verified.

Key privacy properties

  • Unlinkable delegation — Governance nullifiers cannot be linked to standard Orchard nullifiers without knowledge of nk
  • Balance hiding via vote splitting — Ballot count decomposed into 16 independently submitted El Gamal-encrypted shares
  • Individual amounts hidden — Only aggregate totals per (proposal, decision) pair are ever decrypted
  • Vote commitment unlinkability — Blinded per-share commitments prevent linking revealed shares back to a specific VC

Test plan

  • Renders correctly via make draft-valargroup-shielded-voting.html
  • make linkcheck passes for cross-references to Balance Proof, Nullifier PIR, and EA Key Ceremony ZIPs
  • Math notation renders correctly (KaTeX) — especially El Gamal equations, Poseidon hashes, and bitmask operations
  • All sections follow ZIP structure standards (Terminology → Abstract → Motivation → Privacy Implications → Requirements → Specification → Rationale → Deployment → References)
  • BCP 14 keywords appear only in Specification section
  • No conformance requirements outside Specification
  • References are all single-line with correct anchors

p0mvn and others added 30 commits March 4, 2026 19:17
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
The VAN commitment formula was written as a single 7-input Poseidon
hash, but the implementation uses two separate invocations:
ConstantLength<6> for the structural fields, then ConstantLength<2>
to fold in the commitment randomness. These produce different outputs
because each layer finalizes with its own padding before the next
begins.

Split the formula into two steps in all four places it appears: the
VAN data structure definition, VAN integrity in the Delegation Proof,
and old/new VAN integrity in the Vote Proof.
The Share Reveal circuit has 7 public inputs with no anchor_height —
only the Vote Proof (ZKP #2) includes it. The tree root alone is
sufficient to anchor to a specific tree state.

Removed from three places: the Vote Reveal Proof public inputs list,
the out-of-circuit verification step, and the Share Reveal Message
table.
The circuit constrains only the x-coordinates of the El Gamal
ciphertext (two field elements), not full curve points. The full
points are carried in the share reveal message for homomorphic
accumulation during tally, but the ZKP only needs x-coordinates for
the Poseidon-based share commitment binding.

Using full points as public inputs would double the instance cells
for no security gain, and an implementer following the old spec
literally would produce an incompatible circuit.
Shielded voting ZIP: fix spec-vs-implementation discrepancies

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
p0mvn and others added 10 commits March 17, 2026 22:49
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
p0mvn and others added 6 commits March 18, 2026 01:34
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
…are mode

- Phase 3/4 summary: client-chosen submit_at, last-moment single-share
- Share Submission Payload: add submit_at field
- Why N_s Shares: add single-share last-moment exception and rationale
Voting protocol ZIP: client-controlled timing and single-share mode
@str4d str4d removed their request for review March 23, 2026 18:30
@str4d str4d removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 24, 2026
@p0mvn p0mvn force-pushed the roman/voting-protocol branch from b806764 to 1df97ea Compare April 1, 2026 17:57
The voting round identifier was used as an opaque Pallas scalar
input to several Poseidon constructions in this ZIP (van_core,
vc, van_nullifier, gov_null_i, ρ_signed, the Vote Reveal Proof
public inputs) without ever being defined. Specify it as a
deterministic Poseidon hash over the eight setup-field inputs
that uniquely characterise a round.

Place the new subsection at the top of the Data Structures
section, before Vote Authority Note, since voting_round_id is
the most foundational data structure: every other on-chain
construction in this ZIP takes it as an input. Reference the
canonical Poseidon Instantiation section for the parameter set
and add a row for the new hash to its inventory table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@aphelionz aphelionz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some preliminary comments, didn't get through all of it just yet

converts proven Orchard balance into a Vote Authority Note on a
purpose-built vote chain. Second, a *vote proof* consumes a VAN to
produce a Vote Commitment containing $N_s$ El Gamal-encrypted shares of
the voter's ballot count, split across vote options. Third, a *vote

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the first time I'm seeing this term so I'm unclear whether this means the quesdtions on the ballot, the choices per question, or something else. It might be helpful to add "vote option" to Terminology.

Comment on lines +145 to +148
The protocol is motivated by coinholder governance in the Zcash
ecosystem, where participants vote on proposals weighted by their ZEC
holdings. The same mechanism applies to any stake-weighted polling system
over an Orchard-like shielded pool.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section should acknowledge that coinholder polling is but one of many polls including ZCAP and the Engineering Caucus, etc...

**Balance hiding via vote splitting.** A voter's total ballot count is
decomposed into $N_s$ shares encrypted under the election authority's
public key. Each share is submitted independently (potentially via
different submission servers at randomized delays), preventing an

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Underspecified

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants