use crate::{Error, Vec}; use algebra_core::{ bytes::ToBytes, io::{Result as IoResult, Write}, BitIterator, Field, FpParameters, PrimeField, ProjectiveCurve, ToConstraintField, UniformRand, }; use core::marker::PhantomData; use rand::Rng; use super::CommitmentScheme; pub use crate::crh::pedersen::Window; use crate::crh::{pedersen, FixedLengthCRH}; #[cfg(feature = "r1cs")] pub mod constraints; #[derive(Clone)] pub struct Parameters { pub randomness_generator: Vec, pub generators: Vec>, } pub struct Commitment { group: PhantomData, window: PhantomData, } #[derive(Derivative)] #[derivative(Clone, PartialEq, Debug, Eq, Default)] pub struct Randomness(pub C::ScalarField); impl UniformRand for Randomness { #[inline] fn rand(rng: &mut R) -> Self { Randomness(UniformRand::rand(rng)) } } impl ToBytes for Randomness { fn write(&self, writer: W) -> IoResult<()> { self.0.write(writer) } } impl CommitmentScheme for Commitment { type Parameters = Parameters; type Randomness = Randomness; type Output = C::Affine; fn setup(rng: &mut R) -> Result { let time = start_timer!(|| format!( "PedersenCOMM::Setup: {} {}-bit windows; {{0,1}}^{{{}}} -> C", W::NUM_WINDOWS, W::WINDOW_SIZE, W::NUM_WINDOWS * W::WINDOW_SIZE )); let num_powers = ::Params::MODULUS_BITS as usize; let randomness_generator = pedersen::CRH::::generator_powers(num_powers, rng); let generators = pedersen::CRH::::create_generators(rng); end_timer!(time); Ok(Self::Parameters { randomness_generator, generators, }) } fn commit( parameters: &Self::Parameters, input: &[u8], randomness: &Self::Randomness, ) -> Result { let commit_time = start_timer!(|| "PedersenCOMM::Commit"); // If the input is too long, return an error. if input.len() > W::WINDOW_SIZE * W::NUM_WINDOWS { panic!("incorrect input length: {:?}", input.len()); } // Pad the input to the necessary length. let mut padded_input = Vec::with_capacity(input.len()); let mut input = input; if (input.len() * 8) < W::WINDOW_SIZE * W::NUM_WINDOWS { let current_length = input.len(); padded_input.extend_from_slice(input); for _ in current_length..((W::WINDOW_SIZE * W::NUM_WINDOWS) / 8) { padded_input.push(0u8); } input = padded_input.as_slice(); } assert_eq!(parameters.generators.len(), W::NUM_WINDOWS); // Invoke Pedersen CRH here, to prevent code duplication. let crh_parameters = pedersen::Parameters { generators: parameters.generators.clone(), }; let mut result: C = pedersen::CRH::::evaluate(&crh_parameters, &input)?.into(); let randomize_time = start_timer!(|| "Randomize"); // Compute h^r. let mut scalar_bits = BitIterator::new(randomness.0.into_repr()).collect::>(); scalar_bits.reverse(); for (bit, power) in scalar_bits .into_iter() .zip(¶meters.randomness_generator) { if bit { result += power } } end_timer!(randomize_time); end_timer!(commit_time); Ok(result.into()) } } impl> ToConstraintField for Parameters { #[inline] fn to_field_elements(&self) -> Result, Error> { Ok(Vec::new()) } }