arcium-primitives 0.4.5

Arcium primitives
Documentation
use rand::SeedableRng;
use subtle::ConstantTimeEq;

use super::CommitmentScheme;
use crate::{
    algebra::elliptic_curve::{Curve, Point, ScalarAsExtension},
    errors::PrimitiveError,
    hashing::hash,
    random::{BaseRng, CryptoRngCore, Random},
};

#[derive(Copy, Clone, Debug)]
pub struct PedersenCommitment<C: Curve> {
    pub g: Point<C>,
    pub h: Point<C>,
}

impl<C: Curve> PedersenCommitment<C> {
    // Create a new Pedersen commitment scheme by defining the two generators, using the curve's
    // generator as the first generator (g) and the provided seed to derive the second generator
    // (h). Use different seeds to instantiate separate sessions (e.g., with different SessionIds).
    pub fn new<S: AsRef<[u8]>>(second_generator_seed: &S) -> Self {
        let g = Point::generator();
        let mut rng = BaseRng::from_seed(hash(&[second_generator_seed.as_ref()]).into());
        let h = Point::random(&mut rng);
        Self { g, h }
    }
}

impl<C: Curve> CommitmentScheme<ScalarAsExtension<C>> for PedersenCommitment<C> {
    type Commitment = Point<C>;
    type Witness = ScalarAsExtension<C>;

    fn commit<R: CryptoRngCore>(
        &self,
        input: &ScalarAsExtension<C>,
        mut rng: R,
    ) -> (Self::Commitment, Self::Witness) {
        let witness = ScalarAsExtension::<C>::random(&mut rng);

        let commitment = self.g * witness + self.h * input;
        (commitment, witness)
    }

    fn open(
        &self,
        c: &Self::Commitment,
        w: &Self::Witness,
        input: &ScalarAsExtension<C>,
    ) -> Result<(), PrimitiveError> {
        let c_prime = self.g * w + self.h * input;
        if bool::from(c.ct_eq(&c_prime)) {
            Ok(())
        } else {
            Err(PrimitiveError::WrongOpening(
                format!("{c:?}"),
                format!("{c_prime:?}"),
            ))
        }
    }
}