Voters encrypt their selection under the election key, build the (sound)
exponentiation proof binding the ballot to their verification-card key, and
submit to the voting server. The server validates every group element on
receipt, routes the ballot to all four CCs for proof verification, and stores
it only on unanimous acceptance — persisting vcPK (finding F6) so the proof
statement is reconstructible by any party.
- voting.go: castBallot (voter), handleCastBallot (server), handleVerifyBallot
(CC). The CC re-derives the proof statement and verifies it; a malformed proof
or bad group element yields a clean reject, never a panic (the trust-boundary
hardening deferred from the due-diligence pass).
- wire.go: exponentiation-proof DTO.
Tests: 4 ballots flow end-to-end and are stored with vcPK; a ballot with a
zeroed proof is rejected by the CCs and never stored.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pkg/party models each endpoint of the system as a separate object holding only
its own private state, wired together through the transport bus.
- ceremony.go: NewCeremony bootstraps the Ed25519 root CA, enrolls all parties
(setup, 4 CCs, electoral board, voting server, verifier, N voters) with
CA-signed identity certs, registers each in the directory, and wires its
handler into the bus.
- parties.go: the six party types and a shared hello/ack handshake; Handshake()
proves the full sign -> route -> verify -> reply -> verify path for every
party before any election logic runs.
- state.go: per-party private state structs (nothing shared across parties).
- transcript.go: PublicTranscript, the append-only bulletin board a remote
verifier will consume (no secrets).
- phases.go: phase handlers reject unknown message types cleanly (the transport
boundary never panics on unexpected input) — filled in over the next commits.
Transport CA API simplified to own its serial counter (NewCA/Issue).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>