primitives/commitments/
hashbased.rs

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