# ZKP #2 — Vote Proof

> **Status: Needs review by Dev**

## ZKP #2 — Vote Proof

This ZKP proves that a registered voter is casting a valid vote — consuming a VAN, producing a new one with decremented authority, and constructing a vote commitment with encrypted shares.

### Public inputs

* `van_nullifier` — nullifier of the old VAN (prevents double-vote)
* `r_vpk` — randomized voting public key (x, y coordinates)
* `vote_authority_note_new` — the new VAN with decremented proposal authority
* `vote_commitment` — `H(DOMAIN_VC, voting_round_id, shares_hash, proposal_id, vote_decision)`
* `vote_comm_tree_root` — root of the vote commitment tree
* `vote_commitment_tree_anchor_height` — tree snapshot height (validated out-of-circuit by the chain's ante handler; the chain looks up the root at this height and passes it to the verifier)
* `proposal_id` — which proposal
* `voting_round_id`
* `ea_pk` — election authority public key (x, y coordinates). Witnessed into advice cells for in-circuit El Gamal computation, then bound to the instance column via `constrain_instance` so the verifier knows which key was used.

### Witness (private inputs)

* `vote_decision` — the voter's choice
* `vsk.ak` — voting spend auth validating key (Pallas point, analogous to `ak`)
* `vsk.nk` — nullifier deriving key from `vsk` (analogous to `nk`)
* `rivk_v` — CommitIvk randomness for the voting key (analogous to `rivk`)
* `alpha_v` — spend auth randomizer for the voting hotkey (analogous to `alpha`)
* `vpk_g_d` — diversified base from the VAN (analogous to `g_d_signed`; reused for new VAN)
* `vpk_pk_d` — diversified transmission key from the VAN (analogous to `pk_d_signed`; reused for new VAN)
* `total_note_value` — total delegated weight
* `proposal_authority_old`, `proposal_authority_new` — old and new bitmasks
* `gov_comm_rand` — VAN commitment randomness (shared between old and new VAN)
* `vote_comm_tree_path, vote_comm_tree_position` — Merkle proof
* `vote_authority_note_old` — old VAN commitment
* `shares_1, ..., shares_16` — plaintext share values
* `r_1, ..., r_16` — El Gamal encryption randomness (deterministically derived from `sk`, `round_id`, `proposal_id`, `vote_authority_note_old`, and share index via a Blake2b-512 PRF)
* `blind_1, ..., blind_16` — per-share blind factors for blinded share commitments (deterministically derived from the same PRF with a different domain separator)

### Conditions

#### VAN ownership and spending (conditions 1-5)

1. [**Merkle Tree Membership**](https://valargroup.gitbook.io/shielded-vote-docs/circuit-components/merkle-tree-membership) — Old VAN exists in vote commitment tree
2. **VAN Integrity** — `van_comm_core = Poseidon(DOMAIN_VAN, vpk_g_d, vpk_pk_d, total_note_value, voting_round_id, proposal_authority_old)`, then `vote_authority_note_old = Poseidon(van_comm_core, gov_comm_rand)`
3. [**Diversified Address Integrity**](https://valargroup.gitbook.io/shielded-vote-docs/circuit-components/diversified-address-integrity) — `vpk_pk_d = [ivk_v] * vpk_g_d` where `ivk_v = CommitIvk_{rivk_v}(ExtractP(vsk.ak), vsk.nk)`
4. [**Spend Authority**](https://valargroup.gitbook.io/shielded-vote-docs/circuit-components/spend-authority) — `r_vpk = vsk.ak + [alpha_v] * G`
5. [**VAN Nullifier**](https://valargroup.gitbook.io/shielded-vote-docs/circuit-components/van-nullifier) — `van_nullifier` correctly derived from `vsk.nk`

#### New VAN construction (conditions 6-7)

6. [**Proposal Authority Decrement**](https://valargroup.gitbook.io/shielded-vote-docs/circuit-components/proposal-authority-decrement) — Bit `proposal_id` cleared in authority bitmask
7. **New VAN Integrity** — `van_comm_core_new = Poseidon(DOMAIN_VAN, vpk_g_d, vpk_pk_d, total_note_value, voting_round_id, proposal_authority_new)`, then `vote_authority_note_new = Poseidon(van_comm_core_new, gov_comm_rand)`. The new VAN reuses the old VAN's diversified address and commitment randomness; only `proposal_authority` changes. This is safe because VAN commitments are blinded Poseidon hashes — the reused fields are never externally observable, so address rotation would provide no additional unlinkability.

#### Vote commitment construction (conditions 8-12)

8. **Shares Sum Correctness** — `sum(shares_1..16) = total_note_value`
9. [**Shares Range Check**](https://valargroup.gitbook.io/shielded-vote-docs/circuit-components/shares-range-check) — Each share in `[0, 2^30)`
10. [**Shares Hash Integrity**](https://valargroup.gitbook.io/shielded-vote-docs/circuit-components/shares-hash-integrity) — `share_comm_i = H(blind_i, c1_i_x, c2_i_x, c1_i_y, c2_i_y)`, then `shares_hash = H(share_comm_0..15)`
11. [**El Gamal Encryption Integrity**](https://valargroup.gitbook.io/shielded-vote-docs/circuit-components/el-gamal-encryption-integrity) — Each ciphertext validly encrypts its share under `ea_pk`
12. [**Vote Commitment Integrity**](https://valargroup.gitbook.io/shielded-vote-docs/circuit-components/vote-commitment-integrity) — `vote_commitment = H(DOMAIN_VC, voting_round_id, shares_hash, proposal_id, vote_decision)`

### Out-of-circuit checks

* Verify `voteAuthSig` under `r_vpk` over `sighash`
* `van_nullifier` not seen before
* `vote_comm_tree_root` matches published root
* `proposal_id` is valid and in voting window
* `voting_round_id` matches active round
