Skip to content

[ZIP TBD] Shielded Voting Protocol#1200

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

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

Conversation

@p0mvn
Copy link
Copy Markdown

@p0mvn p0mvn commented Mar 5, 2026

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>
@str4d str4d added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 17, 2026
@str4d str4d requested a review from daira March 17, 2026 22:59
p0mvn and others added 15 commits March 17, 2026 21:18
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>
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>
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.

4 participants