# Nouns Private Voting Proposal
# Team + Existing Work
## Background
[Ratan Kaliani](https://twitter.com/ratankaliani) - EECS @ Berkeley (Prev. Polychain, Coinbase)
[Darya Kaviani](https://twitter.com/daryakaviani) - Security R&D Engineer @ Berkeley (Prev. Opyn, Meta)
[Janabel Xia](https://twitter.com/JanabelXia) - Math @ MIT (Prev. Cryptography Researcher @ OSU, UMN)
[Molly Cantillon](https://twitter.com/mollycantillon) - CS+Math @ Stanford (Prev. Microsoft, Constellation Labs)
## Existing Work: zkPoll
### Overview
[zkPoll](http://zkpoll.xyz) is an Ethereum-compatible anonymous polling application. Polls are launched to a subset of ETH users, who can each anonymously vote in the poll using zero-knowledge proofs.
[Semaphore](https://semaphore.appliedzkp.org/) identities allow users to prove their membership of a group and send signals without revealing their original identity. zkPoll integrates the `Semaphore` circuit with [Circom-ECDSA](https://github.com/0xPARC/circom-ecdsa) `PrivToPub` circuit for Ethereum-compatibility. Instead of generating an independent Semaphore secret and identity commitment, ETH users can simply use their private and public key pair.
[GitHub](http://github.com/daryakaviani/zk-poll)
### Benefits of a Ubiquitous Identity
**Convenience:** Poll participants do not need to generate new semaphore secrets, which reduces the resistance to voting and can garner more widespread poll results.
**Subgroup Polls:** Poll coordinators can pass in a Merkle root of an arbitrary ETH subgroup (e.g. a Merkle root of all ETH users who have interacted with a certain protocol or hold a certain token).
**Anonymity Set:** Anonymity is limited to the size of the anonymity set. Subgroup polls enables larger polls. While all users in a Merkle tree may not necessarily vote, this can expand the anonymity set.
### Flow
1. A poll coordinator authenticates to the dApp and creates a poll in the smart contract, passing in a Merkle root of the public addresses in the ETH subgroup.
2. Poll participants generate a zero-knowledge proof using our ECDSA-semaphore circuit that *“I know some* `eth_priv_key` *corresponding to an* `eth_pub_key` *contained in the Merkle Tree.”* The participant submits `{vote, nullifier, proof}` to an [open-source relayer](http://github.com/ratankaliani/zk-poll-relayer), which posts the vote to the smart contract.
1. The voter also submits a public nullifier to the smart contract upon proof submission to prevent double-voting.
3. Users can see the state of each poll (read from the smart contract). In this way, a group’s poll results are generated without revealing who voted for what.
### ECDSA-Semaphore Circuit
Our circuits combine both Semaphore circuits and selected circom-ECDSA circuits. The circuit’s private inputs consist of the user’s ETH private key as well as the Merkle Tree path siblings (as an input to the inclusion proof). The integrated ECDSA PrivtoPub circuit proves that the user has the private key corresponding to their public key, which is then passed into the inclusion proof.
Our current nullifier is calculated as `nullifierHash` = hash(private_key || poll_id), where we use the Poseidon hash. This allows for different nullifiers across different polls, to prevent recovering voter identities from seeing repeated nullifiers across polls.
# Proposal: Integrating zk-nullifier-sig
## zk-nullifier-sig
Currently, users must pass in their private key into the circuit to prove ownership of their public address as well as calculate their nullifier. While burner wallets can be used, we can leverage the concept of digital signatures as a commitment of identity. [Recent work](https://github.com/zk-nullifier-sig/zk-nullifier-sig) allows users to generate a *verifiably-deterministic* signature that has three desirable properties:
- Unique - the signature can serve as a pseudonymous identity
- Verifiable only with the public key (and some randomness) - the user does not need to pass in their private key to generate a proof of verification.
- Deterministic - in order to be useful as a nullifier, the signature must be consistent for each user, since the smart contract would not be able to detect double voting by seeing different signatures from the same person
This signature is also impossible to forge without knowledge of the private key, and keeps the private identity secret. Thus, the deterministic signature serves as a useful nullifier. A user cannot submit a vote twice with distinct nullifiers that are both proven to be verified.
It is important to note that the nullifier alone cannot be verified with just the public key, but requires some randomness (generated from a Fiat-Shamir-like scheme). This ensures that an attacker cannot just try to verify a public nullifier with all the public keys in order to reveal the voter’s identity.
The user would then submit their entire signature (both the deterministic portion and randomness) as well as their public key as private inputs to the circuit. They then generate a proof that their signature was verified, and thus that they have the private key corresponding some public address in the anonymity set.
In order to maintain distinct nullifiers for a single user across polls, we can hash the signature with the externalNullifier = poll_id (unique to each poll).
## Nouns-ification
Currently, we allow for arbitrary merkle roots to be passed in as the “voting groups” for each of the polls. To integrate this into the Nouns voting process, we would take a snapshot of all Nouns holders (and current delegates) who are able to vote at the point of poll creation, and pass that in as the voting group for the specified poll.
The circuit implementation in production currently has ~200K constraints, resulting in a proof generation time of a couple seconds. Integrating the zk-nullifier-sig scheme will result in the circuit having ~4-6M constraints.
## Wallet Integrations
### Current State
Currently, there is a [Metamask Snap](https://metamask.io/news/developers/zk-nullifier-snap-enabling-the-next-generation-of-pseudonymous-apps/) which enables using the zk-nullifier-sig scheme. In order to generate these signatures, users will need to add & enable this extension (until zk-nullifier-sig is implemented in Metamask core).
### Future Work
For this private voting app to work for Nouns holders, we will need to add the zk-nullifier-sig scheme to each wallet provider that Nouns holders use (likely via PR to an open-source repo for a software/firmware update).
- [Metamask PR (WIP)](https://github.com/MetaMask/metamask-extension/pull/17482)
- [ERC Draft](https://www.notion.so/ERC-Draft-f6d584dd2acd414cb6be834e9bdcfbda)
# Contact Information
Ratan Kaliani: @ratankaliani on Twitter, ratan@berkeley.edu