A demonstration of the design in Proposal for a Secure, Private, and Coercion-Resistant Online Voting System. Eight origins, one process — for now.
X4
This is a demonstration, not an election
The voters are fictional and every key in this repository is published on
purpose. Several parts of the design are substituted or absent here, and
each is labelled where it occurs rather than only in a document. Read
docs/Demo_Scope_Limits.md before drawing conclusions from a run.
Every surface carries its own scope clauses, in one of four kinds. The kinds are kept apart because the honest answer to “so it doesn't do that?” is different in each, and an audience that hears one answer for all four stops believing any of them.
| Kind | What it means | The honest answer |
|---|---|---|
| Substituted | Deployment has the real thing; this stands a stub in its place | It does, and this is a stand-in for it. |
| Absent | The design specifies it; this build omits it | The design does, this build doesn't, and here is what it would take. |
| Out of scope | The proposal does not claim it | The proposal doesn't settle that, deliberately. |
| Exposed here | The demo shows what a deployment keeps hidden | Yes, on purpose — so it can be seen rather than taken on trust. |
Hash of the VRO's token signing
key (kp(R)):
| identifier | … |
| choices | … |
| configuration digest | … |
VRO's statement key kp(O) | … |
The configuration digest is SHA-256
over the exact bytes served at election.json — the file as
written, including its indentation and trailing newline, not over a canonical
form or a subset. Download the file and run
shasum -a 256 election.json and you get the value above: it
covers what you actually received.
The fingerprint is of
kp(R), the key every token must verify
under. The setup console
shows the same value. Two surfaces, two glances: the voting application must
not learn which key to trust from the office whose signatures it checks.
A browser origin is scheme, host and port, so separate ports make these genuinely separate — separate script contexts, separate fetch policies, no shared cookies. Six are trust domains; the other two are not. Every page carries a band in its own colour saying which of these it is; the six colours group into three families, and the two that are not trust domains have no colour at all.
| Origin | Serves |
|---|
token-request.json.hash([id, c]) and transmits
[id, c, s] to the office itself. Nothing comes back through
the voting application.c,
unblinds, verifies, marks a ballot and casts it.Two surfaces are not steps in a run. The office's back office shows what the office records beside what it discloses; supervision shows the release register with the identifiers in it. Both exist to be read rather than driven, and a voter reaches neither.
| while voting is open | commitments, positions, the chain head, running counts — and the token-release register as commitments, naming nobody |
| on the voter's own lookup | their ballot record, retrieved by k_p^a, a lookup secret until the close |
| at the close | every record in clear, accepted and rejected alike, and the tally |
| never | the release register's commitments are never opened publicly — their harm is not a running result but a list of who did and did not take part |