Skip to main content

primitives/commitments/
hashbased.rs

1use hybrid_array::Array;
2use subtle::ConstantTimeEq;
3
4use super::CommitmentScheme;
5use crate::{
6    constants::CollisionResistanceBytes,
7    errors::PrimitiveError,
8    hashing::{hash, Digest},
9    random::CryptoRngCore,
10    types::SessionId,
11};
12
13pub type Commitment = Digest;
14pub type Witness = Array<u8, CollisionResistanceBytes>;
15
16#[derive(Default, Copy, Clone, Debug)]
17pub struct HashBasedCommitment {
18    session_id: Option<SessionId>,
19}
20
21impl HashBasedCommitment {
22    pub fn new() -> Self {
23        Self { session_id: None }
24    }
25    pub fn new_with_session_id(session_id: SessionId) -> Self {
26        Self {
27            session_id: Some(session_id),
28        }
29    }
30}
31
32impl<T> CommitmentScheme<T> for HashBasedCommitment
33where
34    T: AsRef<[u8]>,
35{
36    type Commitment = Commitment;
37    type Witness = Witness;
38
39    fn commit<R: CryptoRngCore>(&self, input: &T, mut rng: R) -> (Self::Commitment, Self::Witness) {
40        // 1. Sample the random witness w uniformly at random from {0, 1}^κ.
41        let mut w = Witness::default();
42        rng.fill_bytes(&mut w);
43
44        // 2. Compute the commitment c = H(w || input).
45        let c = match self.session_id {
46            Some(session_id) => hash(&[w.as_ref(), input.as_ref(), session_id.as_ref()]),
47            None => hash(&[w.as_ref(), input.as_ref()]),
48        };
49
50        (c, w)
51    }
52
53    fn open(
54        &self,
55        c: &Self::Commitment,
56        w: &Self::Witness,
57        input: &T,
58    ) -> Result<(), PrimitiveError> {
59        // 1. Compute the commitment c' = H(w || input).
60        let c_prime = match self.session_id {
61            Some(session_id) => hash(&[w.as_ref(), input.as_ref(), session_id.as_ref()]),
62            None => hash(&[w.as_ref(), input.as_ref()]),
63        };
64        // 2. Check if c == c', error otherwise.
65        bool::from(c.ct_eq(&c_prime))
66            .then_some(())
67            .ok_or_else(|| PrimitiveError::WrongOpening(format!("{c:?}"), format!("{c_prime:?}")))
68    }
69}