eczkp 0.1.1

A library for Zero Knowledge Proof protocols using elliptic curves
Documentation
/*
 * eczkp - A library for Zero Knowledge Proof protocols using elliptic curves
 *
 * Copyright (C) 2024 Lucas M. de Jong Larrarte
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */
use crate::error::VerificationFailure;
use rand_core::CryptoRngCore;
use zeroize::ZeroizeOnDrop;

/// A trait representing a cryptographic prover in a zero-knowledge proof protocol.
/// The `Prover` is responsible for generating a commitment and producing an answer
/// to a challenge provided by the verifier, based on its secret.
///
/// # Security Considerations
/// - `Prover` is required to implement `ZeroizeOnDrop` to ensure that sensitive information
///   such as secret keys and nonces are securely wiped from memory when they go out of scope,
///   for example after answering a challenge.
pub trait Prover: Sized + ZeroizeOnDrop {
    /// The type of the secret key used by the prover.
    type SecretKey;
    /// The type of the commitment generated by the prover.
    type Commitment;
    /// The type of the nonce used in the protocol for the prover to commit to.
    type Nonce: Randomized;
    /// The type of the challenge generated by the verifier and responded to by the prover.
    type Challenge;
    /// The type of the answer produced by the prover in response to the verifier's challenge.
    type Answer;

    /// Creates a new `Prover` with a randomly generated nonce.
    ///
    /// # Parameters
    /// - `secret_key`: The secret key of the prover.
    /// - `rng`: A cryptographic random number generator used to generate a random nonce.
    ///
    /// # Returns
    /// A new `Prover` instance.
    ///
    /// This method is typically used to create a `Prover` with a secure random nonce. If you
    /// need to specify the nonce manually, use the `new_with_nonce` method instead.
    fn new(secret_key: &Self::SecretKey, rng: &mut impl CryptoRngCore) -> Self {
        Self::new_with_nonce(secret_key, Self::Nonce::random(rng))
    }

    /// Creates a new `Prover` with a specified nonce.
    ///
    /// # Parameters
    /// - `secret_key`: The secret key of the prover.
    /// - `nonce`: A specific nonce to use during the proof generation.
    ///
    /// # Returns
    /// A new `Prover` instance.
    ///
    /// This method allows to manually specify a nonce, which might be useful if issuing the commitment
    /// and answering a challenge are done in different processes.
    ///
    /// # Warning ⚠️
    /// This method should be used with care. Reuse of the nonce to answer different challenges can have **catastrophic consequences**,
    /// as it exposes the secret key.
    fn new_with_nonce(secret_key: &Self::SecretKey, nonce: Self::Nonce) -> Self;

    /// Returns the nonce used by the prover.
    ///
    /// # Returns
    /// The nonce used in the proof.
    ///
    /// # Warning ⚠️
    /// This method should be used with care. The secret key can be derived from the nonce if a challenge
    /// and the answer to the challenge are known, so exposure of the nonce can have **catastrophic consequences**.
    fn nonce(&self) -> Self::Nonce;

    /// Generates a cryptographic commitment based on the prover's nonce.
    ///
    /// # Returns
    /// The cryptographic commitment.
    fn commitment(&self) -> Self::Commitment;

    /// Consumes the prover and generates an answer to the given challenge.
    ///
    /// # Parameters
    /// - `challenge`: The challenge provided by the verifier.
    ///
    /// # Returns
    /// The answer produced by the prover in response to the challenge.
    ///
    /// # Security Considerations
    /// This method consumes the `Prover` to ensure that the same nonce is not used for
    /// multiple challenges, as reusing a nonce can compromise the secret key.
    fn answer(self, challenge: Self::Challenge) -> Self::Answer;
}

/// A trait representing a cryptographic verifier in a zero-knowledge proof protocol.
/// The `Verifier` is responsible for generating a challenge and verifying the answer
/// produced by the prover.
pub trait Verifier: Sized {
    /// The type of the public key used by the verifier.
    type PublicKey;
    /// The type of the commitment received from the prover.
    type Commitment;
    /// The type of challenge generated by the verifier.
    type Challenge: Randomized;
    /// The type of answer received from the prover.
    type Answer;

    /// Creates a new `Verifier` with a randomly generated challenge.
    ///
    /// # Parameters
    /// - `public_key`: The public key of the prover.
    /// - `commitment`: The commitment received from the prover.
    /// - `rng`: A cryptographic random number generator used to generate a random challenge.
    ///
    /// # Returns
    /// A new `Verifier` instance.
    fn new(
        public_key: &Self::PublicKey,
        commitment: Self::Commitment,
        rng: &mut impl CryptoRngCore,
    ) -> Self {
        Self::new_with_challenge(public_key, commitment, Self::Challenge::random(rng))
    }

    /// Creates a new `Verifier` with a specified challenge.
    ///
    /// # Parameters
    /// - `public_key`: The public key of the prover.
    /// - `commitment`: The commitment received from the prover.
    /// - `challenge`: A specific challenge to use for verification.
    ///
    /// # Returns
    /// A new `Verifier` instance.
    ///
    /// This method allows for specifying a challenge manually, which
    /// might be useful in scenarios where the challenge is generated in a different process
    /// from answer verification.
    fn new_with_challenge(
        public_key: &Self::PublicKey,
        commitment: Self::Commitment,
        challenge: Self::Challenge,
    ) -> Self;

    /// Returns the challenge used by the verifier.
    ///
    /// # Returns
    /// The challenge used in the proof.
    fn challenge(&self) -> Self::Challenge;

    /// Consumes the verifier and verifies the answer provided by the prover against the commitment and challenge.
    ///
    /// # Parameters
    /// - `answer`: The answer provided by the prover.
    ///
    /// # Returns
    /// `Ok(())` if the verification succeeds, or a `VerificationError` if it fails.
    ///
    /// # Security Considerations
    /// This method consumes the verifier to help prevent replay and brute force attacks.
    fn verify(self, answer: Self::Answer) -> Result<(), VerificationFailure>;
}

/// A trait representing objects that can be generated randomly using a cryptographic
/// random number generator. This is typically used for generating nonces and challenges
/// in cryptographic protocols.
///
/// # Security Considerations
/// It is important to ensure that the random number generator passed to `random`
/// is cryptographically secure, as the security of the protocol depends on the
/// unpredictability of the generated values.
pub trait Randomized {
    /// Generates a random instance using the provided cryptographic RNG.
    ///
    /// # Parameters
    /// - `rng`: A cryptographic random number generator.
    ///
    /// # Returns
    /// A randomly generated instance of the implementing type.
    fn random(rng: &mut impl CryptoRngCore) -> Self;
}