Our main aim is a trust-less voting system, where anyone can have a voice and where every component can be audited. We are engineering the necessary building blocks for a permission-less, private, and censorship-resistant democracy.
Our first post presented our principles, vision and mission, this one takes a bird’s-eye view of the technical details of the platform we are building. Our project is constantly evolving, it will be the first in a series of articles in which we present our technical overview.
In Vocdoni’s architecture, each organisation maintains a list of public keys from their potential voters, either in a database or in a public ledger.
These are the steps in which a voting process using Vocdoni is divided:
- Creation of the Voting process: The organiser collates a list of those keys belonging to eligible voters to create a census (for example, members over 16 years old). They hash them using a ZK-Snark friendly hash function (Poseidon) and create a Merkle tree. This data structure, so-called Census, is distributed through a decentralized file-system (IPFS) and the process metadata (including the Merkle root of the census and a process public key for vote encryption) is published on the Ethereum blockchain.
- Casting of votes: Once the process has begun, users can vote. To this aim they will need to provide a valid ‘franchise proof’ in order to demonstrate their eligibility.
1. Without anonymity: Each user will compute its Merkle proof which can be used by the prover to compute the Merkle root of the voting process and thus verify they are part of the census.
2. With anonymity: To satisfy uniqueness and anonymity requirements, each user wraps her ballot in an envelope using a zero-knowledge proof (ZK-Snark).The ZK-Snark proof (franchise proof) is an easy-to-verify method for proving the eligibility of a voter without revealing their identity. That is to say, the method allows a user to convince a third party verifier that it is part of the census and they have not voted twice, without revealing any information about the voter or the vote itself.
- Validation of votes: A custom Tendermint based blockchain is responsible for validating the voting envelope and the franchise proof, to store and account valid ballots. This is referred to as the Voting Chain (Vochain). A ballot is mainly composed of three parts:
- election/process ID
- encrypted or unencrypted vote content
- franchise Proof
Usually data availability is provided by the so-called cloud, which in reality means a centralization of our digital information, gathered by a small set of very powerful companies. Vocdoni aims to be a self-sovereign ecosystem, so we try to enforce the decentralization and distribution of all the non-sensitive data.
Currently, we rely on the ‘InterPlanetary File System’ (IPFS) for storing information. In a voting process we are referring to the text (question, description and options), complementary images, and the census (that can be formed by public keys or user claims). This data doesn’t have to be permanent and it’s expensive to keep it around, so it’s uploaded to IPFS until it can be discarded.
Vocdoni design is modular, so we aim to incorporate more data layers in the future such as Ethersphere Swarm, DAT or STORj.
IPFS does the job, but if no one
pins it when data is uploaded, it will only be available from the origin. To ensure the availability and resilience of the data, a cluster of IPFS nodes pinning the same content should be created.
We started using
ipfs-cluster, but some incompatibilities were found with our architecture. For that reason, we developed a new component named ipfs-sync.
Following a KISS approach, IPFS-sync enables the creation of IPFS clusters in a very quick and easy way. The only required input to create your own cluster is a shared secret, which will be used as a symmetric key to encrypt, authenticate and find other cluster nodes. The current implementation can work either with libp2p/rendezvous and swarm/pss for the p2p transport messaging layer.
Every ipfs-sync node aggregates the list of locally pinned files in a deterministic Merkle tree. The root is broadcasted via the DHT network to those nodes which share the same secret. When a new root is found, the node asks the originator of the message for its list of pins. Thus, all nodes will end up with the same list of files and with the same Merkle tree.
In addition to the data synchronisation, the nodes also announce their Multiaddress via the DHT, so other cluster nodes can directly connect via IPFS.
Would you like to try it?
On a GoLang>1.12 ready environment, just clone our Git repository
git clone https://gitlab.com/vocdoni/go-dvote
And execute ipfsSync with the testing key vocdoni
`go run cmd/ipfsSync/ipfsSync.go --key vocdonidev --dataDir /tmp/vocIpfsSync`
In few seconds ipfsSync should find other cluster nodes and start PINing all files that are currently available on the cluster. If you add a file it will also be replicated on all the rest of the nodes.
ipfs --api=/ip4/127.0.0.1/tcp/5001 add myNewFile.png
Be aware, this ipfsSync cluster currently contains some garbage information (used for testing), so your node will be downloading not useful files.
Data integrity and main coordination
One might call this component the Bible but its name is actually Ethereum.
Ethereum is where all main and most important information is stored, though we try to use it as little as possible for scalability reasons. At the moment, Vocdoni is using the Goerli testnet, but we plan to move the infrastructure to Mainnet once Vocdoni consolidates.
Vocdoni has deployed two smart contracts:
1. Entity resolver smart contract, which contains the metadata of the Entities using Vocdoni. The Ethereum Name Service (ENS) used to address this contract is entity-resolver.vocdoni.eth.
The resolver contract indexes the origin or URI of the entity metadata, among other information.
vnd.vocdoni.eth under the key
entity-id will return the URI (usually IPFS) where the entity description can be found, in JSON format.
In addition, some other records are allowed, such as
vnd.vocdoni.boot-nodes that indicates which boot nodes should be used to reach the rest of the components. If none are specified by the entity, Vocdoni’s default boot nodes will be used.
2. Process management smart contract, used by the entities to publish and manage election processes.
Once an entity (identified by an Ethereum address) wants to create a new process, the entity can send a transaction to this contract containing the basic information required to create it, such as:
- election type (poll, snarks, etc.)
- start and end block number
- URI metadata with the election data information (a JSON file stored on IPFS)
- census Root hash and URI
This contract is monitored by one or many Oracles, the component which makes the bridge between Ethereum and the Vochain.
Voting correctness cannot be guaranteed unless keys really belong to the targeted user. In our identity model the user generates the keys on their device. For this reason, when we talk about identity we like to talk about self-sovereign identity.
Through side channels, the users prove to the organization their eligibility for voting and the ownership of the generated keys. Vocdoni’s design is agnostic to how voters are validated, and organizations can choose their own requirements. We are working on integrating tools to facilitate this process.
At the current stage, Vocdoni uses the well-known plain ECDSA public/private keypairs. As a result, for the time being a user or an entity is globally identified by a public key.
In future posts we will talk more in depth about our identity model, and how it is compatible with existing SSI projects.
The entity has the responsibility of keeping a list of public user keys up-to-date. To this end, Vocdoni provides a Census service, which enables a REST API backend to manage the census in a convenient manner.
The main idea behind the API is allowing the entities to own and manage their private infrastructure. Usually, a database would be storing the real user data such as names, email addresses, and phone numbers. But Vocdoni also provides a very simple, unified web-based solution that can be freely used by any entity.
In our design, the census is a list of ECDSA public keys from eligible voters, aggregated on a Merkle tree using Poseidon hashes (which are ZK-Snarks friendly) based on the iden3 implementation.
Why using a Merkle Tree as a census data structure?
- We can summarize the whole data structure as a single hash
- A user can provide a Merkle proof to demonstrate that its identity is part of the census. For instance, in the example above, the owner of the left-side Pubkey only needs to send its PubKey + Hash4 + Hash2 (named siblings) to allow a third party to reconstruct the root hash. The prover does not need to have access to the whole data structure, just to the root (32 bytes).
Vocdoni aims to scale and support all sizes of voting processes and, in the future, even national elections with millions of eligible voters. To this end we have implemented our own voting blockchain named Vochain.
Our design implies a paradigm shift. Instead of relying on centralized counting systems, our system allows anyone to audit any voting process and at the same time, visualisation tools could be created. Vocdoni has a basic system for this purpose named scrutinizer that anyone can run to verify the correctness of the results.
There are no tokens nor virtual machines on the Vochain; its only purpose is to validate and count votes in a very efficient way. It’s based on Tendermint, so currently it’s a weighted Proof-of-Authority. The nodes (miners or validators) allowed to create new blocks on the Vochain are managed and coordinated in an Ethereum smart contract. Once Vocdoni consolidates our aim is to enable a mixed Proof-of-Authority/Proof-of-Stake in order to decentralize the validators.
The oracle(s) are special Vochain identities able to create a set of special transactions. They act as bridge between Ethereum and the Vochain. So for instance, once a new voting process is created in Ethereum the oracles will send an
addProcess transaction to the Vochain. Although the oracles are trusted components, anyone can verify that they are not manipulated or applying any kind of censorship.
Currently, the Vochain allows the following transactions:
- addProcess: creates a new election process (oracle only)
- cancelProcess: cancels a current election process (oracle only)
- addVote: sends a new vote for an existing process id (voters)
- addOracle: adds a new oracle identified by a pubKey (miners only)
- removeOracle: removes an existing oracle (miners only)
- addValidator: adds a new miner identified by a pubKey (miners only)
- removeValidator: removes an existing miner (miners only)
- addProcessKey: adds an encryption public key for encrypting the votes payload (miners only)
- revelProcessKey: adds an encryption private key for decrypting the votes payload (miners only)
The state of the blockchain is represented by three nested Merkle trees summarised in a single root hash (named State hash). All nodes and miners must calculate the same hash locally. This mechanism ensures that all blockchain bytes are correct and the consensus works. For example, if a new vote is included on block 123 by the miners, the new root hash will be broadcasted on the p2p network. Then, all nodes of the blockchain will validate the same vote, include it, and check that the calculated state matches (if not they will fork).
The vote types currently implemented and allowed are:
- poll: for non-anonymous voting, the voter must provide a valid Merkle proof to demonstrate its eligibility
- snarks: for anonymous voting, the voter must provide a valid ZK-Snark proof (in PoC state )
How do we achieve decentralization
Most of Vocdoni’s components are based on decentralized technologies: IPFS, Ethereum, Tendermint, etc. However all these technologies are very resource-demanding on CPU/Memory and Network. Consequently, running them on a smartphone or in a web environment is not very realistic. To fix this problem we created a component named Gateway.
Gateways provide an entry point to the P2P networks. They allow clients to reach decentralized services through a WebSocket HTTP(s) API interface. The Gateway code can be found on the go-dvote repository. The APIs are defined on the docs page. Currently there are five available APIs that can be enabled/disabled at the Gateway owner’s will, they are:
- file api: provides access to IPFS or any other supported filesystem
- census api: provides access to the census methods, such as create and publish a new census or generate Merkle proof for an eligible voter
- vote api: provides access to the Vochain, for instance to cast a new vote
- results api: if enabled, the Vochain scrutinizer will compute the election results and summarize it for the clients
- web3 api: provides access to the Ethereum blockchain
The Gateways could be added by anyone willing to contribute to the Vocdoni ecosystem but it can also be added by a user who does not trust other Gateways and want to have complete control over its communications. We are working on a Gateway incentivisation mechanism to ensure a good health of the Gateways network.
Once a new Gateway is started it becomes public via a P2P/DHT network (currently libp2p). Bootnodes will check that the Gateway is actually working and will add it to a list. When an APP client needs to reach a Gateway, it will contact the Bootnodes to get this list and choose one (or several). Bootnodes are managed on the entity-resolver smart contract.
Gateways can be attacked, but anyone can set up new ones, so the network scales horizontally, just as any existing blockchain. The integration with DappNode is planned to make Gateways one-click deployable. As a last resort, on a continued DDOS attack, a Gateway can be added privately and silently. So groups or communities can share their own private Gateway infrastructure to ensure they can access the Vocdoni platform.
Would you like to try it?
On a GoLang >1.12 ready environment, just clone our Git repository
git clone https://gitlab.com/vocdoni/go-dvote
And execute the Gateway (check the
--help flag to see all available options)
go run cmd/dvotenode/dvotenode.go --mode=gateway --apiAllowPrivate
The process will start all required Vocdoni services and will expose the Websockets API on port 9090 defined on the documentation page.
How do we ensure user anonymity
Voting anonymity is achieved by the usage of the Zero-knowledge technology Zk-Snarks.
ZK-Snark proofs are a convenient method to prove to third-party verifiers that a voter is within a census and has not voted twice without revealing its identity.
Each Zk-Snark use case requires its own circuit which is shared among provers and verifiers. A circuit is composed mainly by cryptographic operators and indicates, in a strict and deterministic way, if a set of input values is valid or not. To design and implement our circuit we use a non-standard fork of circom (with some minor modifications). Circom is a project developed and maintained by iden3.
Private inputs are those required exclusively when generating a ZK-Snark proof. They are mainly the Merkle proof (that demonstrates a user is part of a census) and the private key (identity of a user). Once the user generates a valid proof for a specific Census Root and ElectionID, it needs to make the Nullifier public together with the Vote package. That nullifier is a unique number that will identify the vote (but not its ownership) thus it will make visible if the same identity is voting twice.
Public inputs are required for validating the Zk-Snark proof, so any prover must have access to these inputs.
- Census Merkle Root
- Vote package (might be encrypted)
- Commit Key
The Commit and Reveal Keys enable a mechanism to mitigate the vote purchase. Once all reveal keys are public anyone can generate a valid Zk-Snark proof for that specific election. So it makes it impossible for a user to demonstrate he voted for a specific option once the election is over.
The commit keys will be generated automatically by the Vochain’s miners once a new election starts and the reveal keys will be published once it finishes. This is one of the weak points of the anonymous voting architecture, but only if all miners agree on tampering with the election results.
How do we enforce transparency
Transparency is a key point in order to enable universal election reliability. A process is end-to-end verifiable if anyone can validate the correctness within the system by its own. The way we use blockchain technology enables the end-to-end verification as, when the voting processes are finished, anyone can download and validate the corresponding Vochain, thus, evaluate if the published results are correct or not.
Although Vocdoni aims to maximise transparency in all its components in order to become trust-less as whole, complete transparency is not always totally possible. There are still some private components which, by nature, require some trust such as the private census of an entity. However, even if the entity tries to manipulate the census, there are some properties that will mitigate these issues:
- Anyone can scrutinise the results of an election, all the votes information (currently often conveniently obfuscated) are stored in the public and open Vochain blockchain. No personal or sensitive data is updated in the blockchain.
- Anyone can check the size of a census, so if the entity tries to add a relevant amount of fake identities to manipulate an election it might be caught by any observer (i.e if a city council has 1000 inhabitants, a census of 1200 identities would show a red flag).
- If an entity replaces an identity on the census, the replaced user will notice it (the vote cannot be sent), so if this happens for a relevant amount of users, the manipulation will be probably discovered.
We are progressively giving MVP access to some small organisations, and we will be extending this invitation as the app and infrastructure get more solid, and we iterate on the UX. 📝Make sure to sign up to be an early tester!
In the current MVP the voting is non-anonymous, which is useful in a lot of scenarios. We are now working on integrating Snarks to anonymise the user as well as encrypting the payload, so results can only be seen at the end of the process.
Join our community!
Vocdoni is a Free Libre and Open Source project currently driven by Dvote-Labs OÜ but aimed to be contributed to by the community. A nonprofit organisation, Vocdoni Roots MTU, is the owner of the code and ensures that the fundamental values of the project are protected.
The infrastructure is conceived as a common good, the code is released under open source AGPLv3, LGPLv2.1 and BSD-3 licenses (depending on the component). More technical and detailed information can be found on the 📑 docs page.
All contributions are welcome! We are a group of people motivated in changing digital governance, and we would love our community to grow! You can 🙋♀️ join us here, participate in the software development in our 🦊 open repositories in Gitlab and apply to the 💼 open positions.
We also invite you to see our technical presentation at the Barcelona Ethereum Dev Meetup!
Header photo by Iker Urteaga on Unsplash