mirror of
https://github.com/saymrwulf/swisspost-evoting-go-poc.git
synced 2026-05-14 20:58:03 +00:00
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.
49 lines
1.4 KiB
Go
49 lines
1.4 KiB
Go
package elgamal
|
|
|
|
import (
|
|
emath "github.com/user/evote/pkg/math"
|
|
)
|
|
|
|
// Decrypt computes the ElGamal decryption of a ciphertext.
|
|
// m_i = phi_i / gamma^sk_i = phi_i * gamma^(-sk_i)
|
|
func Decrypt(ct Ciphertext, sk PrivateKey) Message {
|
|
if ct.Size() != sk.Size() {
|
|
panic("ciphertext size must match secret key size")
|
|
}
|
|
|
|
elems := make([]emath.GqElement, ct.Size())
|
|
for i := 0; i < ct.Size(); i++ {
|
|
// gamma^sk_i
|
|
gammaSk := ct.Gamma.Exponentiate(sk.Get(i))
|
|
// m_i = phi_i / gamma^sk_i
|
|
elems[i] = ct.GetPhi(i).Divide(gammaSk)
|
|
}
|
|
|
|
return Message{Elements: emath.GqVectorOf(elems...)}
|
|
}
|
|
|
|
// PartialDecrypt computes partial decryption using one key share.
|
|
// For each phi: phi_i' = phi_i / gamma^sk_i
|
|
// The gamma is left unchanged for further partial decryptions.
|
|
func PartialDecrypt(ct Ciphertext, sk PrivateKey) Ciphertext {
|
|
if ct.Size() != sk.Size() {
|
|
panic("ciphertext size must match secret key size")
|
|
}
|
|
|
|
phis := make([]emath.GqElement, ct.Size())
|
|
for i := 0; i < ct.Size(); i++ {
|
|
gammaSk := ct.Gamma.Exponentiate(sk.Get(i))
|
|
phis[i] = ct.GetPhi(i).Divide(gammaSk)
|
|
}
|
|
|
|
return Ciphertext{
|
|
Gamma: ct.Gamma,
|
|
Phis: emath.GqVectorOf(phis...),
|
|
}
|
|
}
|
|
|
|
// ExtractMessage extracts the plaintext from a fully decrypted ciphertext.
|
|
// After all partial decryptions, the phis contain the plaintext directly.
|
|
func ExtractMessage(ct Ciphertext) Message {
|
|
return Message{Elements: ct.Phis}
|
|
}
|