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>
wire.go: the validated serialization boundary between parties. Crypto objects
(group elements, public keys, Schnorr proofs, ciphertexts) travel as decimal
DTOs; every decode routes through NewGqElement/NewZqElement so a peer cannot
inject a value outside G_q or Z_q — closing the small-subgroup / non-residue
hole (finding M4) at the trust boundary.
setup.go: RunSetup drives distributed key generation over the bus. Each CC
generates its ElGamal keypair + return-code secret PRIVATELY and returns only
its public key and Schnorr proofs; the setup component verifies every proof on
receipt before combining keys. The electoral board derives its own key and
returns only the public key. Combined election PK and setup artifacts are
published to the public transcript.
Test confirms the combined election key equals the product of the individually
generated CC and EB keys, and that private key material stays with each party
(never appears in the transcript).
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>
Foundation for the multi-party re-architecture: an authenticated, confidential
message transport between the separate parties of the system.
- identity.go: per-party Ed25519 + X25519 identities and an Ed25519 root CA.
Certificates are real X.509, but signed through a crypto.Signer shim whose
Sign() calls the Rust Ed25519 — so x509.CreateCertificate's signature bytes
are produced in Rust. Verification extracts TBS bytes and calls the Rust
verifier, never Go's x509 internals. No RSA anywhere.
- envelope.go: signed inter-party messages over an injective length-prefixed
encoding of all fields; sign/verify via Rust.
- channel.go: X25519 ECDH (Rust) → session key → AES-256-GCM confidential
payloads.
- bus.go: CA-anchored directory + message router that verifies every request
and reply signature before delivery (authenticity enforced at the boundary).
Tests cover cert-chain verification (incl. foreign-CA rejection), envelope
tamper rejection, forged-sender rejection at the bus, and secure-channel
round-trip with associated-data binding.
ARCHITECTURE.md documents the parties, the transport, and the message inventory.
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.