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§

source§

impl<G: Group> LogEqualityProof<G>

source

pub fn new<R: CryptoRng + RngCore>( log_base: &PublicKey<G>, secret: &SecretKey<G>, powers: (G::Element, G::Element), transcript: &mut Transcript, rng: &mut R ) -> Self

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.
source

pub fn verify( &self, log_base: &PublicKey<G>, powers: (G::Element, G::Element), transcript: &mut Transcript ) -> Result<(), VerificationError>

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.

source

pub fn to_bytes(self) -> Vec<u8>

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

source

pub fn from_bytes(bytes: &[u8]) -> Option<Self>

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

Trait Implementations§

source§

impl<G: Clone + Group> Clone for LogEqualityProof<G>
where G::Scalar: Clone,

source§

fn clone(&self) -> LogEqualityProof<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 LogEqualityProof<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 LogEqualityProof<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 LogEqualityProof<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
source§

impl<G: Copy + Group> Copy for LogEqualityProof<G>
where G::Scalar: Copy,

Auto Trait Implementations§

§

impl<G> Freeze for LogEqualityProof<G>
where <G as ScalarOps>::Scalar: Freeze,

§

impl<G> RefUnwindSafe for LogEqualityProof<G>

§

impl<G> Send for LogEqualityProof<G>
where <G as ScalarOps>::Scalar: Send,

§

impl<G> Sync for LogEqualityProof<G>
where <G as ScalarOps>::Scalar: Sync,

§

impl<G> Unpin for LogEqualityProof<G>
where <G as ScalarOps>::Scalar: Unpin,

§

impl<G> UnwindSafe for LogEqualityProof<G>
where <G as ScalarOps>::Scalar: UnwindSafe,

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>,