Around four years ago, I began exploring electronic voting (e-voting) systems by scratching an itch I had. The journey, although challenging, has been enlightening, and I have been focusing on the development of a new e-voting system since I graduated from my PhD program two years ago. Today, I am excited to introduce you to the PeaceFounder project, which is not just another e-voting system but one that aims to raise the bar and overcome the limitations of mainstream E2E verifiable voting systems.
PeaceFounder is built upon the idea of verifiably anonymising voters' pseudonyms rather than their votes. This addresses the tension between security, transparency and privacy without requiring the coordination and meticulous risk assessments of threshold decryption ceremonies. This is achieved by the transactional nature of the anonymisation procedure called braiding, which shuffles and exponentiates all pseudonyms with a secret factor and provides zero-knowledge proof for doing that honestly, much like tying a knot, as shown in the picture.
These proofs are published on the bulletin board for everyone to audit. The PeaceFounder bulletin board is inspired by developments in the auditability of certification authority with history trees, where the goal is to prevent a malicious authority from silently issuing a spoofing certificate, giving a backdoor where it can get your passwords and tokens in plaintext. History tree allows hosting the bulletin board on a single server while member devices keep it accountable to the immutability of records with consistency proofs without needing to do a full replication. This is used for votes, membership certificates, proposals, and braids and, in so, establishes a public transactional log which can be run as a state machine.
Both of these innovations enable a single individual to set up the system, register members, braid pseudonyms, announce proposals and collect votes while neither compromising security, transparency or privacy. On top of that, pseudonymity enables the formation of arbitrary complex ballots, which are no longer limited to human counting workloads. The pseudonymity also enables fluid voting where voters can change their vote at predetermined times, bridging the gap between representative and direct democracy. Also, it is possible to shard a long ballot into smaller sections distributed between voters so that voters have less decision fatigue and are empowered with larger responsibility, resolving the longstanding paradox of voting. Thinking about it keeps me damn excited.
On the technical programming side, PeaceFounder demonstrates Julia's remarkable potential by showcasing its power in full-stack applications, affirming that Julia's capabilities are a reality. Crafting a bridge between Julia and QML was challenging, but I ultimately succeeded when I understood the model-view-controller paradigm. I didn't have to touch a single C++ file or compile anything since
Yggdrasil provided everything out of the box.
I adopted a test-driven development approach, which involved drafting an API for components to synergise before diving into Julia for implementation. I made a conscious effort to avoid brittle wrappers, leading to the reimplementation of the Verificatum-compatible proof of shuffle, which was initially only available in Java. Additionally, I chose to implement cryptographic groups and signatures in Julia instead of using C library wrappers.
Throughout the project, I prioritised purity and simplicity. Packages like CryptoSignatures, ShuffleProofs, and HistoryTrees embody these principles with a narrow API that lifts mountains behind them. However, this rule was broken with CryptoGroups, which could be scrambled in many tiny packages and thus, writing documentation for it is a chore. This reminds me of a mistake I made early on in the project by registering many small packages like
DiffieHellman. As a result, only 30% of packages have evolved and survived. Nonetheless, I plan to revive some of these in the future, ending with about 50% survivals and improving this rather ugly situation.
Currently, a demo of PeaceFounder is available without voiceover commentary that allows for a quick grasp of the project's essence and preliminary status. The upcoming milestones include the development of an administrative panel and a seamless user interface that eliminates the need for terminal interactions.
As with any endeavour of such magnitude, challenges abound. Over recent months, I have been invested in clarifying the project's purpose and edge over competitors and articulating design intricacies, now available at peacefounder.org. This was a good time to take a step back from development to get back in with revived vigour. With essential documentation in place, the PeaceFounder project has reached a milestone where the Julia community can make a difference. Your feedback, scrutiny, and potential coding improvements are welcomed. Specific areas of code contribution are outlined on peacefounder.org/roadmap.
I recognise that Julia emphasises high-performance tasks, which drove my decision to exclusively use it for numerical computations, leveraging the powerful
QuantumOptics during my PhD. While developing the PeaceFounder project, I never felt inclined to switch to languages like Python, C, C++, or Rust. The interactive development facilitated by tools like
Infiltrator expedited the creation of the demo.
Looking ahead, the static compilation issue is a dealbreaker since I wish to deploy the client to mobile. Currently, it seems I will need to port the client backend in Rust, which could interface with an already written QML facade and offer Arti a TOR client library necessary to prevent traceability. Nevertheless, I don't look at my decision to do the project in Julia as a mistake, as it enabled me to iterate quickly and put the ideas into a form with a Julia's type system. It also puts me on a frontier for writing high-performance cryptography where, for instance, proof of shuffle (see
ShuffleProofs) is a highly parallelisable algorithm which can benefit from being run on an HPC cluster for a large-scale application.
In addition, I have faced some other gripes, such as the hurdle of direct module importing without erasing global variables. This makes me hesitant to adopt
Oxygen within a module, as a hack is needed, as highlighted in this issue. Another difficulty I face is documenting highly overloaded methods where I wish the code could be stricter, perhaps with something like a trait/interface. The dynamics around type parameter values and the need to bypass the
isbitstype requirement have also been limiting. Using
Mods as an example, type parameters conveniently store the modulus, allowing for compact vector representation, but fails with
BigInt. I use this extensively in ShuffleProofs.jl, which gets me to write pseudocode while allowing me to raise errors at the dispatch stage when groups are not aligned.
In conclusion, PeaceFounder embodies years of dedication, research, and personal growth. I would greatly appreciate to receive feedback, scrutiny, and potential coding improvements. A GitHub star on PeaceFounder.jl would also not hurt :) On the horizon, I'm gearing up to present a poster at the EVoteID conference in Luxembourg. Also, as my personal resources start to run dry, I'm actively seeking financial support and would appreciate anyone who could mentor me through this.
Originally published on Julia Forem