V
live demo — post-quantum · homomorphic · verifiable

the vote is
visible
silent.

A working demonstration of a homomorphic voting system. Every ballot is encrypted at the source under a key nobody holds. The server tallies the ciphertexts without ever reading a single vote. Only the final totals are ever decrypted — and only by a quorum of trustees, together, after the polls close.

§ 01

what a homomorphic ballot is

— part 01  ·  the ring, the key, the trustees

A key nobody holds

Three trustees each draw a small random polynomial. Their sum is the election's decryption key — but no one ever assembles it. Each publishes a public share plus a zero-knowledge proof that their share is small (a large one would let them read ballots unilaterally).

— part 02  ·  a ballot is a vector of ciphertexts

One encrypted bit per candidate

Your ballot is C ciphertexts, one per candidate. Each encrypts either 0 or 1. The client attaches a proof that (a) every ciphertext really encrypts a bit — not 47 — and (b) the bits sum to exactly 1. No amount of grinding produces a valid stuffed ballot.

— part 03  ·  addition without decryption

The server tallies ciphertexts

BFV/Ring-LWE is additively homomorphic: the encryption of a+b is the sum of the encryptions of a and b. The server adds every accepted ballot component-wise — and cannot read any of them, ever.

— part 04  ·  thresholded decryption of the totals

Only the totals come out

After closing, each trustee publishes a partial decryption of the aggregate ciphertext, with a proof it was done with their real key share. Anyone can combine them into the per-candidate counts — which are the only plaintexts the system ever produces.

§ 02

cast a ballot

polls open

Loading election…

§ 03

the public bulletin board

loading…
§ 04

close, tally, announce

before tally, only the aggregate ciphertext exists. After the three trustees each publish a proven partial decryption:

no tally yet
§ 05

verify it yourself

Every claim above — the trustee keys, the cast ballots, the aggregate, the tally — is on the board and can be re-derived from scratch. The universal verifier does exactly that: it downloads the board, re-runs every check, and reports what it found.

Download the raw board (JSON)