Zero-Knowledge Proof Based Onchain Private Voting
ETHBarcelona Talks · July 2024 · 13:20
Ahmad Afuni explains how zero-knowledge proofs can power private voting onchain. The talk covers keeping ballots secret while still letting anyone verify the result, and what that means for DAO governance. The goal is votes that are anonymous yet publicly auditable. Presented at ETHBarcelona.
Speakers
Topics
From ETHBarcelona Talks, hosted by ETH Barcelona.
Transcript
uh make our final speaker of the day feel super super welcome he's going to talk about zero knowledge proof-based onchain private voting put your hands together for Ahmed afuni hi so I'll be talking about some joint work um that we the Aragon ZK research team have been doing with Aztec as part of nouns Down's uh private research Sprint so I'll be yeah introducing stuff talking about the design and implementation and outlook for the future so as an introduction um
well huh this is a bit strange I actually need to go up and down here I don't suppose you have a clicker that supports that or maybe a keyboard cuz else I can't really can any of you hit the down arrow I had the for maybe I'll snap my fingers yeah for me the head just go down if I do this go down so I'm sorry about that no you want to go down no yeah there we go I'll snap my fingers for the next next one so tldrs we have a token based voting system with a stay over here so we've got a token based voting system um voter anonymity
is built in for Life hopefully um votes are shielded till the end of the voting period and everything is verified onchain snap my fingers no just that and so the ideal workflow is the following we uh have prospective uh voters enroll to vote a proposal is made and put to a vote and um voters then submit their vote at the end of the voting period uh votes are decrypted Tally's computed results are published and diagrammatically it looks
like this we basically have so this right right AR Arrow basically goes towards the future register to vote uh voting process is created and then whole bunch of votes are submitted private key is revealed at some later point in time and that marks the end of the voting period and then the results are computed and published so let me go on to the design and implementation down and here's an overview of how that goes down please um we have a locally generated private key for enrollment so here's the thing you want to use your Hardware wallet most likely you need some form of a private key to be verified in circuit to show that you know you actually or or locally
on your computer you need to do some computations compute some signatures that may not necessarily be standard so we have a separate private key for that please go down um we have a Time locked public private key pair so there's a Time locked service to assum is god-given reveals a public key at the initial time and at some later point in time we get a private key that way the votes are actually encrypted to the end please go down votes may be submitted by anyone so here's where the anonymity comes in anybody can submit a vote as long as they submit the relevant ZK proofs verifying that they actually own the nft that is associated with the vote and also that they've you know actually enrolled to vote so all these things are linked together in a ZK circuit please
go down and um all of this is based on verifying storage proofs inside a ZK circuit please go down and here's how the setup goes um we have an ethereum the ethereum blockchain we could have poly well not polygon in this case but we have ethereum please go down we have a fixed ERC 721 contract henceforth the nft contract we have a ZK snark proving system in our case for our setting it's Ultra plon with an underlying field you know the usual altb uh 128 um embedded curve uh in this case is baby Jubjub whose order or at least a subgroup of baby Jubjub whose order should be small
enough for convenience and we should have the possibility of onchain verification we have a ZK snark friendly hash function H which is posiden for us uh another hash function H1 used for um used for aggregation and finally a time lock service for verifiably random key generation in order to hide the votes and there are a few contracts associated with this process first of all we have the registry contract so all it has is a mapping from addresses to public keys in this case baby jujub public Keys um and uh we have a voting contract which is where all the magic happens um where you actually um start a voting process uh submit your votes submit and actually
you know submit the results and um I mean it has some built-ins like the registry and nft contract addresses but then for each voting process we need specifiers to actually specify the vote and this is where the god-given public key comes in um we also have ballots stored in there but suitably uh encrypted and I'll go into more detail as to how that's done as well as proofs of Eligibility that are submitted along with each vote and aggregation of votes as they come in so we basically reduce these encrypted votes using this hash function H1 Kack in the best case for lower gas costs but then Poseidon for better circuit integration and finally we um also include the results after
everything is tallied and in addition to these two contracts we have verifier smart contracts to actually verify these circuits these proofs that are submitted and so the workflow for each contract pretty much looks like this for each of at least the first two contracts which call out to the verifier contracts we run a computation locally on our machine maybe in the browser someday soon hopefully um and generate a ZK proof we submit the public inputs of this um ZK proof computation together with the ZK proof to the contract things are verified and data stored on the contract and so let's go into each of the individual contracts so registration is simple enough the steps are as
follows you generate a private key Zed on this embedded curve you compute the corresponding public key and then you submit this public key to the registry from the address owning the nft so I mean you assume that pretty much everyone would enroll to vote but this is where the I guess linking of addresses to votes stops because in the next step the voting process creation we do the following well I mean this will not actually give us anonymity just yet somebody has to start the voting process and they would submit the following to the voting contract first of all the parameters relevant to the voting process so title description vote choices maybe yes no abstain that's our initial implementation duration of the
voting period they would submit they would actually state that all of the the registrations should be relative to some point in time given as a block number and I'll talk more about this later it should be a recent one the most recent one in the best case and from within the contract we can compute the block hash but we can't actually compute we can't actually pull out the state route or any storage routes within the evm those have to be supplied and this is where you have to submit these to the contract relative to block n and you also have to submit a ZK proof that actually links this block hash over to the state route and also to those storage routes and this will come in later when each person casts their vote and um in addition we have to you know specify a public key
which everyone would use to encrypt their votes so the voting process will then go as follows for vote V associated with address a process ID um process ID being basically the uh process n so the vote voting process number um and the specifics of the contract to you know to link it up to this particular voting process and for nft with ID given by ID nft the voter should do the following first compute signatures so a signature involving the nft ID and uh the voting process ID and one involving uh the uh the the uh uh public key uh sorry not the public key the the
vote itself um the uh second step is to compute the nullifier from this first signature involving the ID of the nft this is to prevent double voting much like double spending I mean it's the same trick um we generate a random private key R and compute a new public key a um and then a shared secret relative to this private key and the uh uh the the private key of the um time Lock Service of the basically the key used to encrypt the votes we encrypt the vote V using this hash scheme so we use Poseidon in our case and we basically um do it relative to the shared secret and uh we uh then also obtain storage proofs uh basically linking the
address to ownership of this nft with id id nft and also linking the address to the public key Z corresponding to this private key used to sign everything and we generate a ZK proof Pi of this whole computation so basically verify signatures compute nullifier Etc um and we use these underlined quantities so basically this this public key a um the encrypted vote and the nullifier we basically uh submit those as public inputs and finally we take all of this we take this the public inputs and the proof p and we submit those to the voting contract and that's how you
vote and now well once the voting process is over what do we do how do we you know compute the results well at this point we're given the private key corresponding to this public key us to encrypt all the votes and uh we obtain these uh pairs Ai and bi so basically the public keys for the individual votes and also the individual votes in in encrypted form and now what we can do is we can compute the shared secret because we actually have the private key corresponding yeah from the time Lock Service and we Brute Force decrypt each bi to obtain the relevant vote then we can compute the results of the voting process and then we compute the aggregation um so what happens is along the way as the smart contract gets all
the votes it actually Aggregates by Computing by basically uh reducing a list of all the uh submitted votes encrypted votes um reducing it by means of this hash function H1 which would be is actually posidon in our current code but it could just is what would be katak depending on your trade-offs and what we do is we generate a ZK proof verifying these steps with public inputs uh the ident identifier of the whole process and these underlying variables and then we submit this proof together with the public inputs to the voting contract to publish the results so this there are a few Alles involved in all of the above um and you may have already picked up on
them first of all Tri proofs are very expensive in a ZK snark so it actually takes I mean on the order of 10 minutes to do each of those proofs for the voting process and for actually you know casting your vote and uh there's also a gas proving cost balance you have to you have to strike a balance between gas cost and proving time or proof size depending on what hash function you choose for example and another challenge is saving the whales so whales with tons of NTS could cast a whole bunch of votes in quick succession and then you'd be able to figure out who actually cast the vote right so you might want to hide the
identity of a whale so you might need a relayer service in between time delayed in order to you know preserve the identities of these to yeah just hide the identities of these whales so our Outlook is that we are actually producing a proof of concept should be out pretty soon and um we're looking at optimizing our circuits and all of our codes so that everything runs sufficiently quickly there's also the other well actually let me go on to the next point the last uh part of our Outlook is Dow integration actually integrating this into a dow into well here at so over at Aragon we have our own Dow deployment framework and it would be nice if we actually if
this could be plugged into that into the plug-in system and that is on our road map um and yeah I mean this is pretty much where we plan to go and I've actually gone through the whole talk so thank you for your [Applause] attention