sigma-protocols 0.5.1

SIGMA zero-knowledge proof protocols
Documentation
//! Pedersen commitment opening proof.
//!
//! Proves knowledge of the opening (value and randomness) of a Pedersen commitment.
//! Specifically, proves knowledge of (v, r) such that C = v * G + r * H.

use curve25519_dalek::ristretto::RistrettoPoint;
use curve25519_dalek::scalar::Scalar;

use crate::error::{Error, Result};
use crate::sigma::{MultiScalarResponse, PointCommitment, ScalarChallenge, SigmaProtocol};
use crate::utils::{random_scalar, scalar_from_state};

/// Public statement for Pedersen commitment proof.
///
/// Contains the two base points and the commitment.
#[derive(Clone, Debug)]
pub struct PedersenStatement {
    pub g: RistrettoPoint,
    pub h: RistrettoPoint,
    pub commitment: RistrettoPoint,
}

/// Private witness for Pedersen commitment proof.
///
/// Contains the committed value and the randomness used.
#[derive(Clone, Debug)]
pub struct PedersenWitness {
    pub value: Scalar,
    pub randomness: Scalar,
}

/// Pedersen commitment opening proof implementation.
///
/// Proves knowledge of (v, r) such that C = v * G + r * H.
pub struct PedersenProof;

impl SigmaProtocol for PedersenProof {
    type Statement = PedersenStatement;
    type Witness = PedersenWitness;
    type Commitment = PointCommitment;
    type Challenge = ScalarChallenge;
    type Response = MultiScalarResponse;

    fn prover_commit(
        statement: &Self::Statement,
        _witness: &Self::Witness,
    ) -> (Self::Commitment, Vec<u8>) {
        let r_v = random_scalar();
        let r_r = random_scalar();
        let commitment = r_v * statement.g + r_r * statement.h;

        let mut state = Vec::with_capacity(64);
        state.extend_from_slice(&r_v.to_bytes());
        state.extend_from_slice(&r_r.to_bytes());

        (PointCommitment(commitment), state)
    }

    fn prover_response(
        _statement: &Self::Statement,
        witness: &Self::Witness,
        state: &[u8],
        challenge: &Self::Challenge,
    ) -> Result<Self::Response> {
        if state.len() != 64 {
            return Err(Error::InvalidProof);
        }

        let r_v = scalar_from_state(&state[0..32])?;
        let r_r = scalar_from_state(&state[32..64])?;

        let s_v = r_v + challenge.0 * witness.value;
        let s_r = r_r + challenge.0 * witness.randomness;

        Ok(MultiScalarResponse(vec![s_v, s_r]))
    }

    fn verifier(
        statement: &Self::Statement,
        commitment: &Self::Commitment,
        challenge: &Self::Challenge,
        response: &Self::Response,
    ) -> Result<()> {
        if response.0.len() != 2 {
            return Err(Error::InvalidResponse);
        }

        let s_v = response.0[0];
        let s_r = response.0[1];

        let lhs = s_v * statement.g + s_r * statement.h;

        let rhs = commitment.0 + challenge.0 * statement.commitment;

        if lhs == rhs {
            Ok(())
        } else {
            Err(Error::InvalidProof)
        }
    }
}