pub struct LogEqualityProof<G: Group> { /* private fields */ }
Expand description

Zero-knowledge proof of equality of two discrete logarithms in different bases, aka Chaum–Pedersen protocol.

Construction

This proof is a result of the Fiat–Shamir transform applied to a standard ZKP of equality of the two discrete logs in different bases.

  • Public parameters of the proof are the two bases G and K in a prime-order group in which discrete log problem is believed to be hard.
  • Prover and verifier both know group elements R and B, which presumably have the same discrete log in bases G and K respectively.
  • Prover additionally knows the discrete log in question: r = dlog_G(R) = dlog_K(B).

The interactive proof is specified as a sigma protocol (see, e.g., this course) as follows:

  1. Commitment: The prover generates random scalar x. The prover sends to the verifier X_G = [x]G and X_K = [x]K.
  2. Challenge: The verifier sends to the prover random scalar c.
  3. Response: The prover computes scalar s = x + cr and sends it to the verifier.

Verification equations are:

[s]G ?= X_G + [c]R;
[s]K ?= X_K + [c]B.

In the non-interactive version of the proof, challenge c is derived from hash(M), where hash() is a cryptographically secure hash function, and M is an optional message verified together with the proof (cf. public-key digital signatures). If M is set, we use a proof as a signature of knowledge. This allows to tie the proof to the context, so it cannot be (re)used in other contexts.

To reduce the size of the proof, we use the trick underpinning ring signature constructions. Namely, we represent the proof as (c, s); during verification, we restore X_G, X_K from the original verification equations above.

Implementation details

  • The proof is serialized as 2 scalars: (c, s).
  • Proof generation is constant-time. Verification is not constant-time.
  • Challenge c is derived using Transcript API.

Examples

let mut rng = thread_rng();
let (log_base, _) =
    Keypair::<Ristretto>::generate(&mut rng).into_tuple();
let (power_g, discrete_log) =
    Keypair::<Ristretto>::generate(&mut rng).into_tuple();
let power_k = log_base.as_element() * discrete_log.expose_scalar();

let proof = LogEqualityProof::new(
    &log_base,
    &discrete_log,
    (power_g.as_element(), power_k),
    &mut Transcript::new(b"custom_proof"),
    &mut rng,
);
proof.verify(
    &log_base,
    (power_g.as_element(), power_k),
    &mut Transcript::new(b"custom_proof"),
)?;

Implementations

Creates a new proof.

Parameters
  • log_base is the second discrete log base (K in the notation above). The first log base is always the Group generator.
  • secret is the discrete log (r in the notation above).
  • powers are [r]G and [r]K, respectively. It is not checked whether r is a discrete log of these powers; if this is not the case, the constructed proof will not verify.

Verifies this proof.

Parameters
  • log_base is the second discrete log base (K in the notation above). The first log base is always the Group generator.
  • powers are group elements presumably equal to [r]G and [r]K respectively, where r is a secret scalar.
Errors

Returns an error if this proof does not verify.

Serializes this proof into bytes. As described above, the is serialized as 2 scalars: (c, s), i.e., challenge and response.

Attempts to parse the proof from bytes. Returns None if bytes do not represent a well-formed proof.

Trait Implementations

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

Deserialize this value from the given Serde deserializer. Read more

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

Should always be Self

The resulting type after obtaining ownership.

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

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

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.