pub struct CommitmentEquivalenceProof<G: Group> { /* private fields */ }
Expand description
Zero-knowledge proof that an ElGamal ciphertext encrypts the same value as a Pedersen commitment.
This proof can be used to switch from frameworks applicable to ElGamal ciphertexts, to ones applicable to Pedersen commitments (e.g., Bulletproofs for range proofs).
§Construction
We want to prove in zero knowledge the knowledge of scalars r_e
, v
, r_c
such as
R = [r_e]G; B = [v]G + [r_e]K;
// (R, B) is ElGamal ciphertext of `v` for public key `K`
C = [v]G + [r_c]H;
// C is Pedersen commitment to `v`
Here, we assume that the conventional group generator G
is shared between encryption and
commitment protocols.
An interactive version of the proof can be built as a sigma protocol:
- Commitment. The prover generates 3 random scalars
e_r
,e_v
ande_c
and commits to them viaE_r = [e_r]G
,E_b = [e_v]G + [e_r]K
, andE_c = [e_v]G + [e_c]H
. - Challenge. The verifier sends to the prover random scalar
c
. - Response. The prover computes the following scalars and sends them to the verifier.
s_r = e_r + c * r_e;
s_v = e_v + c * v;
s_c = e_c + c * r_c;
The verification equations are
[s_r]G ?= E_r + [c]R;
[s_v]G + [s_r]K ?= E_b + [c]B;
[s_v]G + [s_c]H ?= E_c + [c]C;
A non-interactive version of the proof is obtained by applying Fiat–Shamir transform. As with other proofs, it is more efficient to represent a proof as the challenge and responses (i.e., 4 scalars in total).
§Examples
let blinding_base = // Blinding base for Pedersen commitments
// (e.g., from Bulletproofs)
let mut rng = thread_rng();
let (receiver, _) = Keypair::<Ristretto>::generate(&mut rng).into_tuple();
// Create an ElGamal ciphertext of `value` for `receiver`.
let value = 424242_u64;
let ciphertext = CiphertextWithValue::new(value, &receiver, &mut rng)
.generalize();
// Create a blinding factor for the Pedersen commitment of the same value.
let blinding = SecretKey::generate(&mut rng);
let (proof, commitment) = CommitmentEquivalenceProof::new(
&ciphertext,
&receiver,
&blinding,
blinding_base,
&mut Transcript::new(b"custom_proof"),
&mut rng,
);
// Use `commitment` and `blinding` in other proofs...
proof.verify(
&ciphertext.into(),
&receiver,
commitment,
blinding_base,
&mut Transcript::new(b"custom_proof"),
)?;
Implementations§
source§impl<G: Group> CommitmentEquivalenceProof<G>
impl<G: Group> CommitmentEquivalenceProof<G>
sourcepub fn new<R: RngCore + CryptoRng>(
ciphertext: &CiphertextWithValue<G>,
receiver: &PublicKey<G>,
commitment_blinding: &SecretKey<G>,
commitment_blinding_base: G::Element,
transcript: &mut Transcript,
rng: &mut R
) -> (Self, G::Element)
pub fn new<R: RngCore + CryptoRng>( ciphertext: &CiphertextWithValue<G>, receiver: &PublicKey<G>, commitment_blinding: &SecretKey<G>, commitment_blinding_base: G::Element, transcript: &mut Transcript, rng: &mut R ) -> (Self, G::Element)
Creates a proof based on the ciphertext
for receiver
and commitment_blinding
with commitment_blinding_base
for a Pedersen commitment. (The latter two args
correspond to r_c
and H
in the Construction section, respectively.)
§Return value
Returns a proof together with the Pedersen commitment.
sourcepub fn verify(
&self,
ciphertext: &Ciphertext<G>,
receiver: &PublicKey<G>,
commitment: G::Element,
commitment_blinding_base: G::Element,
transcript: &mut Transcript
) -> Result<(), VerificationError>
pub fn verify( &self, ciphertext: &Ciphertext<G>, receiver: &PublicKey<G>, commitment: G::Element, commitment_blinding_base: G::Element, transcript: &mut Transcript ) -> Result<(), VerificationError>
§Errors
Returns an error if this proof does not verify.
Trait Implementations§
source§impl<G: Clone + Group> Clone for CommitmentEquivalenceProof<G>
impl<G: Clone + Group> Clone for CommitmentEquivalenceProof<G>
source§fn clone(&self) -> CommitmentEquivalenceProof<G>
fn clone(&self) -> CommitmentEquivalenceProof<G>
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more