# Shielded Voting — Changes vs Upstream Shielded governance voting for Zodl iOS. ZEC holders vote on governance proposals using zero-knowledge proofs that prove eligibility (note ownership at a snapshot height) without revealing identity or balance. Four repos, layered bottom-up. One new library, three PRs against existing repos. ## Specification Six draft ZIPs define the protocol: | ZIP PR | Title | | ------------------------------------------------ | ----------------------------------------------------------------------------- | | [#1200](https://github.com/zcash/zips/pull/1200) | Shielded Voting Protocol (core — delegation, voting, share submission, tally) | | [#1199](https://github.com/zcash/zips/pull/1199) | Orchard Proof-of-Balance | | [#1198](https://github.com/zcash/zips/pull/1198) | Private Information Retrieval for Nullifier Exclusion Proofs | | [#1201](https://github.com/zcash/zips/pull/1201) | Election Authority Key Ceremony | | [#1203](https://github.com/zcash/zips/pull/1203) | Shielded Coinholder Voting (setup) | | [#1218](https://github.com/zcash/zips/pull/1218) | Submission Server (temporal mixing) | ## Architecture ``` zodl-ios (Swift/TCA) └─ zcash-swift-wallet-sdk (SPM) ├─ VotingRustBackend.swift (wraps C FFI) └─ libzcashlc.a (Rust staticlib) ├─ librustzcash ← wallet DB queries └─ librustvoting ← voting DB, ZKP proofs, encryption ``` librustvoting never touches the wallet DB. The SDK FFI queries notes/witnesses via librustzcash and passes them to librustvoting as arguments. This is the key separation of concerns — librustzcash owns the wallet domain, librustvoting owns the voting domain, and the SDK wires them together. --- ## 1. librustzcash — [zcash/librustzcash#2212](https://github.com/zcash/librustzcash/pull/2212) **Branch:** `shielded-voting-wallet-support` → `maint/zcash_client_sqlite-0.19.x` **Diff:** 7 files, +280 Minimal surface area addition — two read-only PCZT getters and two governance-specific `WalletDb` methods (inherent, not on wallet traits): - **`get_orchard_notes_at_snapshot()`** — backward-looking note query at a historical snapshot height - **`generate_orchard_witnesses_at_frontier()`** — generates Merkle witnesses anchored at a historical frontier using an ephemeral in-memory DB (wallet DB is read-only) - **PCZT getters** — `spend_auth_sig` (read back HW wallet signature for ZK proof), `shielded_sighash` (backport from main) No new traits, no modifications to existing APIs. --- ## 2. librustvoting — [valargroup/librustvoting](https://github.com/valargroup/librustvoting) **New repo**, no upstream counterpart. Three workspace crates: core library, vote commitment tree, tree sync client. Voting protocol implementation: hotkey derivation, governance PCZT construction, Halo2 ZKP proofs (delegation + vote), ElGamal vote encryption, PIR nullifier exclusion, vote commitment tree sync, SQLite round-state persistence. **Key design decision:** no dependency on `zcash_client_sqlite` or `zcash_client_backend`. All wallet data arrives as function arguments — any wallet implementation can use it. Dependencies: [voting-circuits](https://github.com/valargroup/voting-circuits) (orchard fork with governance ZKP gadgets), librustzcash crates for PCZT/key types. --- ## 3. zcash-swift-wallet-sdk — [zcash/zcash-swift-wallet-sdk#1657](https://github.com/zcash/zcash-swift-wallet-sdk/pull/1657) **Branch:** `shielded-vote` → `main` **Diff:** 12 files, +6,064/−524 The glue layer. 52 `extern "C"` FFI functions in `rust/src/voting.rs` + Swift wrappers (`VotingRustBackend.swift`, `VotingTypes.swift`). Four FFI functions do wallet↔voting plumbing (open `WalletDb`, query notes/witnesses via librustzcash, convert to librustvoting types). The remaining ~48 are thin pass-throughs to librustvoting. Complex types cross the boundary via JSON serde; encrypted share secrets are stripped at the FFI boundary. One new SDK API: `getTreeState(height:)` on `Synchronizer` for commitment tree witness generation. --- ## 4. zodl-ios — [zodl-inc/zodl-ios#1659](https://github.com/zodl-inc/zodl-ios/pull/1659) **Branch:** `shielded-vote` → `main` **Diff:** 63 files, +8,843/−194 Pure application layer — no direct FFI or wallet DB access. Five new SPM modules (`Voting`, `VotingModels`, `VotingAPIClient`, `VotingCryptoClient`, `VotingStorageClient`) plus `BackgroundTaskClient` for keeping the app alive during ZKP generation. Core is `VotingStore`, a ~2,400-line TCA reducer managing the full lifecycle: delegation (PCZT → ZKP → on-chain TX), voting (commitment tree sync → vote commitment → encrypted share distribution), multi-bundle support, Keystone hardware wallet signing, and crash recovery with all intermediate state persisted to SQLite. Server communication uses 3-tier service discovery, per-server circuit breaker health tracking, and client-side `submit_at` timestamp sampling for share distribution privacy. Tests: ~715 lines covering delegation flow, Keystone pipeline, 6 crash recovery scenarios, and TX event parsing. --- ## Back-end protocol implementation | Repo | Purpose | | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | | [vote-sdk](https://github.com/valargroup/vote-sdk) | Cosmos SDK application chain — delegation TX processing, vote commitment verification, tally | | [voting-circuits](https://github.com/valargroup/voting-circuits) | Halo2 circuits for delegation and vote proofs (orchard fork) | | [vote-nullifier-pir](https://github.com/valargroup/vote-nullifier-pir) | PIR server for nullifier non-membership proofs | | [vote-shielded-vote-generator-ui](https://github.com/valargroup/vote-shielded-vote-generator-ui) | Admin UI for voting round/proposal management | ## Merge order 1. **librustzcash** — independent, no voting deps 2. **librustvoting** — independent repo, cargo patches should align with merged librustzcash 3. **zcash-swift-wallet-sdk** — depends on 1 + 2 4. **zodl-ios** — depends on 3