Skip to main content

primitives/commitments/
mod.rs

1use crate::{errors::PrimitiveError, random::CryptoRngCore};
2
3pub mod hashbased;
4pub mod pedersen;
5
6pub trait CommitmentScheme<InputT> {
7    type Commitment: Clone;
8    type Witness: Default + Clone;
9
10    fn commit<R: CryptoRngCore>(&self, input: &InputT, rng: R)
11        -> (Self::Commitment, Self::Witness);
12    fn open(
13        &self,
14        commitment: &Self::Commitment,
15        witness: &Self::Witness,
16        input: &InputT,
17    ) -> Result<(), PrimitiveError>;
18}
19
20#[cfg(test)]
21mod tests {
22    use rand::SeedableRng;
23
24    use super::{hashbased, pedersen};
25    use crate::{
26        algebra::elliptic_curve::{Curve25519Ristretto as C, ScalarAsExtension},
27        commitments::CommitmentScheme,
28        hashing::hash,
29        random::{test_rng, BaseRng, Random, Seed},
30        types::SessionId,
31    };
32
33    /// Test that a commitment can be opened successfully.
34    pub fn test_happypath_commitment_opens_ok<InputT, C: CommitmentScheme<InputT>>(
35        commitment_scheme: &C,
36        input_generator: impl Fn(Seed) -> InputT,
37    ) {
38        let input = input_generator([0u8; 32]);
39        let mut rng = test_rng();
40
41        let (c, w) = commitment_scheme.commit(&input, &mut rng);
42        assert!(commitment_scheme.open(&c, &w, &input).is_ok());
43    }
44
45    /// Test that a commitment cannot be opened with a different input, or with mismatched
46    /// commitments and witnesses.
47    pub fn test_unhappypath_wrong_or_mismatched_dont_open<InputT, C: CommitmentScheme<InputT>>(
48        commitment_scheme: &C,
49        input_generator: impl Fn(Seed) -> InputT,
50    ) {
51        let input = input_generator([1u8; 32]);
52        let mut rng = test_rng();
53
54        let (c, w) = commitment_scheme.commit(&input, &mut rng);
55
56        // Try to open with a different input.
57        let second_input = input_generator([2u8; 32]);
58        assert!(commitment_scheme.open(&c, &w, &second_input).is_err());
59
60        // Try to open mismatched commitments and witnesses.
61        let (c2, w2) = commitment_scheme.commit(&input, &mut rng);
62        assert!(commitment_scheme.open(&c, &w2, &input).is_err());
63        assert!(commitment_scheme.open(&c2, &w, &input).is_err());
64    }
65
66    #[test]
67    pub fn test_commitment_scheme_hashbased() {
68        let session_id = SessionId::random(test_rng());
69        let commitment_scheme = hashbased::HashBasedCommitment::new_with_session_id(session_id);
70        let input_generator = |seed: Seed| hash(&[seed.as_ref()]);
71
72        test_happypath_commitment_opens_ok(&commitment_scheme, input_generator);
73        test_unhappypath_wrong_or_mismatched_dont_open(&commitment_scheme, input_generator);
74    }
75
76    #[test]
77    pub fn test_commitment_scheme_pedersen() {
78        let commitment_scheme =
79            pedersen::PedersenCommitment::<C>::new(b"Nothing-up-my-sleeve generator h");
80        let input_generator = |seed: Seed| {
81            let mut rng = BaseRng::from_seed(seed);
82            ScalarAsExtension::<C>::random(&mut rng)
83        };
84
85        test_happypath_commitment_opens_ok(&commitment_scheme, input_generator);
86        test_unhappypath_wrong_or_mismatched_dont_open(&commitment_scheme, input_generator);
87    }
88}