Return-code base: use prime^Σk (algebraic) instead of HashAndSquare

Changes the choice-code base from HashAndSquare(prime_i) to the encoding prime
itself (a G_q element). The card code becomes prime_i^{Σ_j k_j}, which is
algebraic and therefore recomputable by the CCs directly from the submitted
ciphertext at vote time — the prerequisite for a genuine cast-as-intended
return-code path. Setup and (upcoming) vote-time extraction use the same base,
keeping them consistent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
saymrwulf 2026-07-06 15:45:01 +02:00
parent 895782543c
commit 577205a2ff

View file

@ -64,8 +64,15 @@ func (p *ControlComponent) handleLongCodeShare(env *transport.Envelope) (*transp
if !ok {
return nil, fmt.Errorf("cc%d: invalid prime %q", p.index, ps)
}
hpCC := hash.HashAndSquare(prime, group)
choiceShares[i] = hpCC.Exponentiate(kChoice).Value().String()
// Base is the encoding prime itself (a G_q element), NOT a hash of it:
// this keeps the code base algebraic so the CCs can recompute prime^k
// homomorphically from the submitted ciphertext at vote time
// (cast-as-intended). The combined card code is prime_i^{Σ_j k_j}.
base, err := emath.NewGqElement(prime, group)
if err != nil {
return nil, fmt.Errorf("cc%d: prime %d not in group: %w", p.index, i, err)
}
choiceShares[i] = base.Exponentiate(kChoice).Value().String()
}
// Confirmation-code share, keyed off a per-voter confirmation key.