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    use rand_chacha::ChaCha12Rng as ChaChaRng;
24
25    use super::{hashbased, pedersen};
26    use crate::{
27        algebra::elliptic_curve::{Curve25519Ristretto as C, ScalarAsExtension},
28        commitments::CommitmentScheme,
29        hashing::hash,
30        random::{self, Prng, Random},
31        types::SessionId,
32    };
33
34    /// Test that a commitment can be opened successfully.
35    pub fn test_happypath_commitment_opens_ok<InputT, C: CommitmentScheme<InputT>>(
36        commitment_scheme: &C,
37        input_generator: impl Fn(u64) -> InputT,
38    ) {
39        let input = input_generator(0);
40        let mut rng = ChaChaRng::from_seed(
41            hash(&[b"It's like the great stories, Mr. Frodo, the ones that really mattered."])
42                .into(),
43        );
44
45        let (c, w) = commitment_scheme.commit(&input, &mut rng);
46        assert!(commitment_scheme.open(&c, &w, &input).is_ok());
47    }
48
49    /// Test that a commitment cannot be opened with a different input, or with mismatched
50    /// commitments and witnesses.
51    pub fn test_unhappypath_wrong_or_mismatched_dont_open<InputT, C: CommitmentScheme<InputT>>(
52        commitment_scheme: &C,
53        input_generator: impl Fn(u64) -> InputT,
54    ) {
55        let input = input_generator(1);
56        let mut rng = random::test_rng();
57
58        let (c, w) = commitment_scheme.commit(&input, &mut rng);
59
60        // Try to open with a different input.
61        let second_input = input_generator(2);
62        assert!(commitment_scheme.open(&c, &w, &second_input).is_err());
63
64        // Try to open mismatched commitments and witnesses.
65        let (c2, w2) = commitment_scheme.commit(&input, &mut rng);
66        assert!(commitment_scheme.open(&c, &w2, &input).is_err());
67        assert!(commitment_scheme.open(&c2, &w, &input).is_err());
68    }
69
70    #[test]
71    pub fn test_commitment_scheme_hashbased() {
72        let session_id =
73            SessionId::from_hashed_seed(b"I will take the Ring though I do not know the way.");
74        let commitment_scheme = hashbased::HashBasedCommitment::new_with_session_id(session_id);
75        let input_generator = |seed: u64| hash(&[seed.to_be_bytes().as_ref()]);
76
77        test_happypath_commitment_opens_ok(&commitment_scheme, input_generator);
78        test_unhappypath_wrong_or_mismatched_dont_open(&commitment_scheme, input_generator);
79    }
80
81    #[test]
82    pub fn test_commitment_scheme_pedersen() {
83        let commitment_scheme =
84            pedersen::PedersenCommitment::<C>::new(b"the Ring is trying to get back to its master");
85        let input_generator = |seed: u64| {
86            let mut rng = ChaChaRng::from_hashed_seed(seed.to_be_bytes());
87            ScalarAsExtension::<C>::random(&mut rng)
88        };
89
90        test_happypath_commitment_opens_ok(&commitment_scheme, input_generator);
91        test_unhappypath_wrong_or_mismatched_dont_open(&commitment_scheme, input_generator);
92    }
93}