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:

  1. Commitment. The prover generates 3 random scalars e_r, e_v and e_c and commits to them via E_r = [e_r]G, E_b = [e_v]G + [e_r]K, and E_c = [e_v]G + [e_c]H.
  2. Challenge. The verifier sends to the prover random scalar c.
  3. 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>

source

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.

source

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>
where G::Scalar: Clone,

source§

fn clone(&self) -> CommitmentEquivalenceProof<G>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<G: Debug + Group> Debug for CommitmentEquivalenceProof<G>
where G::Scalar: Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'de, G: Group> Deserialize<'de> for CommitmentEquivalenceProof<G>

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl<G: Group> Serialize for CommitmentEquivalenceProof<G>

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,