sigma_protocols/protocols/
pedersen.rs

1//! Pedersen commitment opening proof.
2//!
3//! Proves knowledge of the opening (value and randomness) of a Pedersen commitment.
4//! Specifically, proves knowledge of (v, r) such that C = v * G + r * H.
5
6use curve25519_dalek::ristretto::RistrettoPoint;
7use curve25519_dalek::scalar::Scalar;
8use rand::rngs::OsRng;
9use rand::TryRngCore;
10
11use crate::error::{Error, Result};
12use crate::sigma::{MultiScalarResponse, PointCommitment, ScalarChallenge, SigmaProtocol};
13
14/// Public statement for Pedersen commitment proof.
15///
16/// Contains the two base points and the commitment.
17#[derive(Clone, Debug)]
18pub struct PedersenStatement {
19    pub g: RistrettoPoint,
20    pub h: RistrettoPoint,
21    pub commitment: RistrettoPoint,
22}
23
24/// Private witness for Pedersen commitment proof.
25///
26/// Contains the committed value and the randomness used.
27#[derive(Clone, Debug)]
28pub struct PedersenWitness {
29    pub value: Scalar,
30    pub randomness: Scalar,
31}
32
33/// Pedersen commitment opening proof implementation.
34///
35/// Proves knowledge of (v, r) such that C = v * G + r * H.
36pub struct PedersenProof;
37
38impl SigmaProtocol for PedersenProof {
39    type Statement = PedersenStatement;
40    type Witness = PedersenWitness;
41    type Commitment = PointCommitment;
42    type Challenge = ScalarChallenge;
43    type Response = MultiScalarResponse;
44
45    fn prover_commit(
46        statement: &Self::Statement,
47        _witness: &Self::Witness,
48    ) -> (Self::Commitment, Vec<u8>) {
49        let mut r_v_bytes = [0u8; 32];
50        OsRng
51            .try_fill_bytes(&mut r_v_bytes)
52            .expect("Failed to generate random bytes");
53        let r_v = Scalar::from_bytes_mod_order(r_v_bytes);
54        let mut r_r_bytes = [0u8; 32];
55        OsRng
56            .try_fill_bytes(&mut r_r_bytes)
57            .expect("Failed to generate random bytes");
58        let r_r = Scalar::from_bytes_mod_order(r_r_bytes);
59
60        let commitment = r_v * statement.g + r_r * statement.h;
61
62        let mut state = Vec::with_capacity(64);
63        state.extend_from_slice(&r_v.to_bytes());
64        state.extend_from_slice(&r_r.to_bytes());
65
66        (PointCommitment(commitment), state)
67    }
68
69    fn prover_response(
70        _statement: &Self::Statement,
71        witness: &Self::Witness,
72        state: &[u8],
73        challenge: &Self::Challenge,
74    ) -> Result<Self::Response> {
75        if state.len() != 64 {
76            return Err(Error::InvalidProof);
77        }
78
79        let mut r_v_bytes = [0u8; 32];
80        let mut r_r_bytes = [0u8; 32];
81        r_v_bytes.copy_from_slice(&state[0..32]);
82        r_r_bytes.copy_from_slice(&state[32..64]);
83
84        let r_v_option = Scalar::from_canonical_bytes(r_v_bytes);
85        let r_r_option = Scalar::from_canonical_bytes(r_r_bytes);
86
87        let r_v = if r_v_option.is_some().unwrap_u8() == 1 {
88            r_v_option.unwrap()
89        } else {
90            return Err(Error::InvalidScalar);
91        };
92
93        let r_r = if r_r_option.is_some().unwrap_u8() == 1 {
94            r_r_option.unwrap()
95        } else {
96            return Err(Error::InvalidScalar);
97        };
98
99        let s_v = r_v + challenge.0 * witness.value;
100        let s_r = r_r + challenge.0 * witness.randomness;
101
102        Ok(MultiScalarResponse(vec![s_v, s_r]))
103    }
104
105    fn verifier(
106        statement: &Self::Statement,
107        commitment: &Self::Commitment,
108        challenge: &Self::Challenge,
109        response: &Self::Response,
110    ) -> Result<()> {
111        if response.0.len() != 2 {
112            return Err(Error::InvalidResponse);
113        }
114
115        let s_v = response.0[0];
116        let s_r = response.0[1];
117
118        let lhs = s_v * statement.g + s_r * statement.h;
119
120        let rhs = commitment.0 + challenge.0 * statement.commitment;
121
122        if lhs == rhs {
123            Ok(())
124        } else {
125            Err(Error::InvalidProof)
126        }
127    }
128}