This is a non-interactive zero-knowledge proof of knowedge (NIZKPoK) protocol to prove that you know the preimage of an El Gamal ciphertext. More specifically, it allows a prover to convince a verifier that a commitment is of the preimage of an El Gamal ciphertext. This protocol can be useful in situations where you want to prove knowledge of what the encrypted message is without revealing the data.
This is a work in progress and not safe for production use.
Build and test the project with cargo:
cargo build
cargo test
Example with JubJub (see the tests).
let mut rng = test_rng();
// the secret key
let x = <JubJub as Group>::ScalarField::rand(&mut rng);
let g: JubJub = JubJub::generator().into();
// the public key
let h: JubJub = g.mul(x).into();
let params = Params { g, h };
let (commitment, ciphertext, proof) =
ElGamalSigmaProtocol::prove(x, params.clone(), test_rng());
let result =
ElGamalSigmaProtocol::verify(commitment, ciphertext, proof, params);
assert_eq!(result, true);
This section contains technical details on how the protocol works.
A sigma protocol is an interactive public 3-move public coin flip protocol where a prover convinces a verifier that they know the witness
The protocol works over elliptic curves. Let
Let
Prover
- Encrypt the message
$s$ for the public key$H$ using El Gamal:$(c_1, c_2) = (kG, s(kH))$ where$k \xleftarrow{R} \mathbb{Z}_q$ - Calculate a (Pedersen) commitment
$c = sG + sH$ - Choose
$r \xleftarrow{R} \mathbb{Z}_q$ and set$t = kG$ ,$a = kH$ . - Compute
$e = H(t, a, c_1, c_2, AUX)$ - Set
$z = k + es$ - Send
$(t, a, z, c, c_1, c_2)$ to the verifier.
Verifier
- Compute
$e = H(t, a, c_1, c_2, AUX)$ - Check if
$zG + zH == t + a + e*c$ . If so, output$1$ , otherwise output$0$ .
This works since: