Prototypes BallotP36 · Verifiable election

The public board

Every event of the election, in the order the server appended it. Each entry holds the SHA-256 of the entry before it, so removing or changing an entry changes every hash after it. Press an entry to see what it holds.

Election
#EntryHashPoints to

An entry

Press an entry.
How Ballot is built
  1. Ballot is an election where the server never sees a vote. Each ballot is encrypted in the voter’s browser, the server adds the encrypted ballots together, and the trustees decrypt only the total. The cryptography is written for this prototype in plain JavaScript with BigInt, with no dependencies.
  2. The curve is NIST P-256, the one WebCrypto and most TLS use. Ballot has its own field arithmetic, point addition and doubling, scalar multiplication with a window that does the same work for every scalar, a precomputed table for the generator, and SEC1 encoding with the check that a point is on the curve.
  3. A vote for a candidate is 1 and every other candidate gets 0, each encrypted with exponential ElGamal under the election key. Adding two ciphertexts adds the votes inside them, so the server can total the ballots without opening one.
  4. The browser adds zero-knowledge proofs to each ballot, made non-interactive with Fiat-Shamir over SHA-256: each number is 0 or 1, and the numbers add up to exactly one. Every proof is bound to the election and to the voter’s code, so it cannot be copied into another ballot or another election.
  5. A voter code never leaves the browser. It gives a key whose public half is on the election’s list, and the ballot is signed with it. The server checks the code is listed and unused, but cannot change a ballot or make one for a code it does not hold.
  6. The election key is made by three trustees without a dealer: each shares a random line with Feldman commitments, checks the shares it receives, and names a trustee whose share does not match. Any two trustees decrypt the total by Lagrange interpolation, each with a proof that they used their real share.
  7. The board is a log chained with SHA-256. A voter’s receipt is the hash of their ballot, which they can find on the board. The verifier reads only the board and checks every proof, the total added up again, each partial decryption and the result. Four flawed servers show it catching a dropped, changed or added ballot and a wrong total.
  8. It is judged against other implementations: the unit tests compare its scalar multiplication and point encoding with node’s P-256 for hundreds of random scalars, and the verifier page compares it with this browser’s WebCrypto. A property test plays random elections that must verify, and flawed ones that must be caught.
  9. Its limits: Ballot is a demo, and no authority has certified it for elections. The vote is in the clear on the voter’s device until the browser encrypts it, so malware on that device could read or change it. The person who hands out the codes knows which code went to whom: they can see that a person voted, and the encryption hides the choice from them. Two trustees who work together could decrypt one ballot instead of the total. The prototype has no defense against a voter who is watched or paid while voting, and BigInt arithmetic is not constant time.