mirror of
https://github.com/saymrwulf/swisspost-evoting-go-poc.git
synced 2026-09-05 20:30:43 +00:00
The running cryptography now narrates itself. Each headline operation emits a
trace.Event carrying its LaTeX notation plus the actual runtime values, the
instant it executes:
- Ed25519 signature on every inter-party message (envelope.Seal)
- X25519 ECDH key agreement for confidential card delivery (NewSecureChannel)
- ElGamal ballot encryption E1 = (g^r, pk^r·m) with the real r (castBallot)
- Fiat-Shamir challenge e = H(...) mod q (Schnorr proof)
- Bayer-Groth verifiable shuffle C' = {ReEnc_pk(C_π(i))} with N (mix-net)
Ceremony phases set trace phase/party context so events are attributed to the
acting stakeholder and phase. Instrumentation is behind the enabled-check, so
normal runs pay nothing.
Test: a full traced ceremony captures 184 live events across all five headline
kinds, each with non-empty LaTeX and live values, correctly phase/party-tagged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
70 lines
1.8 KiB
Go
70 lines
1.8 KiB
Go
package mixnet
|
||
|
||
import (
|
||
"fmt"
|
||
|
||
"github.com/user/evote/pkg/elgamal"
|
||
emath "github.com/user/evote/pkg/math"
|
||
"github.com/user/evote/pkg/trace"
|
||
)
|
||
|
||
// VerifiableShuffle holds the result of a verifiable shuffle.
|
||
type VerifiableShuffle struct {
|
||
ShuffledCiphertexts *elgamal.CiphertextVector
|
||
Argument ShuffleArgument
|
||
}
|
||
|
||
// GenVerifiableShuffle performs a shuffle and generates a proof.
|
||
func GenVerifiableShuffle(
|
||
C *elgamal.CiphertextVector,
|
||
pk elgamal.PublicKey,
|
||
group *emath.GqGroup,
|
||
) VerifiableShuffle {
|
||
// Determine matrix dimensions
|
||
N := C.Size()
|
||
_, n := GetMatrixDimensions(N)
|
||
|
||
// Generate commitment key of size n
|
||
ck := GenCommitmentKey(n, group)
|
||
|
||
// Perform shuffle
|
||
shuffle := GenShuffle(C, pk)
|
||
|
||
// Generate shuffle argument
|
||
arg := GenShuffleArgument(C, shuffle.Shuffled, shuffle.Perm, shuffle.Rho, pk, ck, group)
|
||
|
||
trace.EmitFunc(func() trace.Event {
|
||
return trace.Event{
|
||
Kind: trace.KindShuffle,
|
||
Caption: fmt.Sprintf("Bayer-Groth verifiable shuffle of %d ciphertexts", N),
|
||
LaTeX: `\mathbf{C}' = \big\{\, \mathrm{ReEnc}_{pk}\!\big(C_{\pi(i)};\, \rho_i\big) \,\big\}_{i=1}^{\VAL{N}}, \qquad \pi \xleftarrow{\$} S_{\VAL{N}}`,
|
||
ASCII: "C' = { ReEnc_pk(C_π(i); ρ_i) } for a secret permutation π",
|
||
Values: map[string]string{
|
||
"N": fmt.Sprintf("%d", N),
|
||
"m": fmt.Sprintf("%d", N/n),
|
||
"n": fmt.Sprintf("%d", n),
|
||
},
|
||
}
|
||
})
|
||
|
||
return VerifiableShuffle{
|
||
ShuffledCiphertexts: shuffle.Shuffled,
|
||
Argument: arg,
|
||
}
|
||
}
|
||
|
||
// VerifyShuffle verifies a verifiable shuffle.
|
||
func VerifyShuffle(
|
||
C *elgamal.CiphertextVector,
|
||
vs VerifiableShuffle,
|
||
pk elgamal.PublicKey,
|
||
group *emath.GqGroup,
|
||
) bool {
|
||
N := C.Size()
|
||
_, n := GetMatrixDimensions(N)
|
||
|
||
// Regenerate commitment key (deterministic from group)
|
||
ck := GenCommitmentKey(n, group)
|
||
|
||
return VerifyShuffleArgument(vs.Argument, C, vs.ShuffledCiphertexts, pk, ck, group)
|
||
}
|