# 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**](/shielded-vote-docs/circuit-components/merkle-tree-membership.md) — 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**](/shielded-vote-docs/circuit-components/diversified-address-integrity.md) — `vpk_pk_d = [ivk_v] * vpk_g_d` where `ivk_v = CommitIvk_{rivk_v}(ExtractP(vsk.ak), vsk.nk)`
4. [**Spend Authority**](/shielded-vote-docs/circuit-components/spend-authority.md) — `r_vpk = vsk.ak + [alpha_v] * G`
5. [**VAN Nullifier**](/shielded-vote-docs/circuit-components/van-nullifier.md) — `van_nullifier` correctly derived from `vsk.nk`

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

6. [**Proposal Authority Decrement**](/shielded-vote-docs/circuit-components/proposal-authority-decrement.md) — 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**](/shielded-vote-docs/circuit-components/shares-range-check.md) — Each share in `[0, 2^30)`
10. [**Shares Hash Integrity**](/shielded-vote-docs/circuit-components/shares-hash-integrity.md) — `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**](/shielded-vote-docs/circuit-components/el-gamal-encryption-integrity.md) — Each ciphertext validly encrypts its share under `ea_pk`
12. [**Vote Commitment Integrity**](/shielded-vote-docs/circuit-components/vote-commitment-integrity.md) — `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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://valargroup.gitbook.io/shielded-vote-docs/zkp-specifications/zkp2-vote-proof.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
