arcium-primitives 0.4.4

Arcium primitives
Documentation
use hybrid_array::Array;
use subtle::ConstantTimeEq;

use super::CommitmentScheme;
use crate::{
    constants::CollisionResistanceBytes,
    errors::PrimitiveError,
    hashing::{hash, Digest},
    random::CryptoRngCore,
    types::SessionId,
};

pub type Commitment = Digest;
pub type Witness = Array<u8, CollisionResistanceBytes>;

#[derive(Default, Copy, Clone, Debug)]
pub struct HashBasedCommitment {
    session_id: Option<SessionId>,
}

impl HashBasedCommitment {
    pub fn new() -> Self {
        Self { session_id: None }
    }
    pub fn new_with_session_id(session_id: SessionId) -> Self {
        Self {
            session_id: Some(session_id),
        }
    }
}

impl<T> CommitmentScheme<T> for HashBasedCommitment
where
    T: AsRef<[u8]>,
{
    type Commitment = Commitment;
    type Witness = Witness;

    fn commit<R: CryptoRngCore>(&self, input: &T, mut rng: R) -> (Self::Commitment, Self::Witness) {
        // 1. Sample the random witness w uniformly at random from {0, 1}^κ.
        let mut w = Witness::default();
        rng.fill_bytes(&mut w);

        // 2. Compute the commitment c = H(w || input).
        let c = match self.session_id {
            Some(session_id) => hash(&[w.as_ref(), input.as_ref(), session_id.as_ref()]),
            None => hash(&[w.as_ref(), input.as_ref()]),
        };

        (c, w)
    }

    fn open(
        &self,
        c: &Self::Commitment,
        w: &Self::Witness,
        input: &T,
    ) -> Result<(), PrimitiveError> {
        // 1. Compute the commitment c' = H(w || input).
        let c_prime = match self.session_id {
            Some(session_id) => hash(&[w.as_ref(), input.as_ref(), session_id.as_ref()]),
            None => hash(&[w.as_ref(), input.as_ref()]),
        };
        // 2. Check if c == c', error otherwise.
        bool::from(c.ct_eq(&c_prime))
            .then_some(())
            .ok_or_else(|| PrimitiveError::WrongOpening(format!("{c:?}"), format!("{c_prime:?}")))
    }
}