The mix-net now runs across separate parties over the signed transport: the
server pads the ballot box and hands it to CC0; each CC shuffles + partially
decrypts and passes the (validated) ciphertexts to the next; the electoral
board performs the final shuffle + decryption. Ciphertext handoffs cross the
authenticated transport; each party posts its shuffle and decryption proofs to
the public transcript (the bulletin board).
- tally.go: RunTally orchestration + per-party handlers (server pad, CC shuffle,
EB final decrypt). Persists the padded mix input and per-stage partial
decrypts to the transcript (fixes F7/F8 in the multi-party setting).
- verify.go: RunVerify has the verifier independently re-check every CC Schnorr
proof and the whole shuffle chain from the transcript alone (no secrets).
- returncodes: DecodeVoteChecked returns an error instead of panicking on a
non-smooth plaintext (fixes F12), used on the tally path so a corrupt ballot
is counted as spoiled rather than crashing the tally.
Tests: the full ceremony (setup -> cards -> voting -> tally -> verify) produces
the correct tally over 124 verified transport messages; the verifier rejects a
transcript with swapped Schnorr proofs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Setup now generates each voter's return-code card by collecting shares from all
four CCs over the bus (the GenEncLongCodeShares exchange) and distributes cards
and the mapping table over CONFIDENTIAL channels.
- codes.go: deriveReturnCodeKey is the SINGLE key-derivation function used by a
CC both when contributing to card assembly and (later) at vote-time extraction
— structurally preventing the setup/extraction derivation mismatch (F1). Each
CC computes its choice/confirm shares from its private return-code secret;
only the shares (validated as G_q members on decode) cross the bus.
- RunCards assembles cards, registers mapping-table entries, and delivers cards
to voters + the mapping table to the server via sendConfidential (X25519 ECDH
session key + AES-256-GCM, then Ed25519-signed) — exercising the secure
channel in the ceremony, not just in tests.
- returncodes: MappingTable Export/ImportMappingTable for transport.
Test confirms every voter receives its card confidentially with the right code
count and the server receives the full mapping table + public election keys.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Correctness/security review of the whole PoC, with fixes and regression tests.
Cryptographic soundness:
- mixnet: enforce the multi-exponentiation c_{B_m}=commit(0;0) check that was
stubbed out with an empty if — without it a malicious mixer can prove a
non-permutation shuffle.
- zkp: derive all four Fiat-Shamir challenges via RecursiveHashToZq instead of
a biased `hash mod q` (which also capped the challenge space at 256 bits for
production-sized groups).
Verification honesty:
- protocol: VerifyTally now actually calls zkp.VerifySchnorrProof and returns
the true aggregate result instead of an unconditional true.
- protocol: persist the padded mix input (event.MixInput) so the verifier checks
shuffle 0 against the same padding the tally used (fixes false INVALID for N<2).
Other correctness:
- kdf: length-prefix BuildKDFInfo parts so the info encoding is injective.
- math: GqElementFromSquareRoot accepts the valid root q (off-by-one that could
panic in HashAndSquare); RandomGqElement samples the full canonical range.
- cmd: validate demo --voters/--options instead of panicking on degenerate values.
- protocol: use crypto/rand in the demo driver (drop the last math/rand import).
Transport security (new): pkg/transportsec exposes Ed25519 signatures and X25519
ECDH — implemented in Rust (rust/transportsec: ed25519-dalek, x25519-dalek),
linked into Go via cgo. No RSA. Cross-language conformance test proves the Rust
Ed25519 signatures interoperate with Go's crypto/ed25519. Makefile builds the
Rust static lib before the Go binary.
Tests: added unit/round-trip/tamper coverage for math, hash, elgamal, zkp,
mixnet, kdf, returncodes, protocol (end-to-end), and the Rust FFI bridge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Proof-of-concept reimplementation of the Swiss Post e-voting
cryptographic protocol in Go. Single binary, 52 source files,
2 dependencies. Covers ElGamal encryption, Bayer-Groth verifiable
shuffles, zero-knowledge proofs, return codes, and a full
election ceremony demo.