use crate::{Error, Vec}; use core::{ fmt::{Debug, Formatter, Result as FmtResult}, marker::PhantomData, }; use rand::Rng; #[cfg(feature = "parallel")] use rayon::prelude::*; use crate::crh::FixedLengthCRH; use algebra_core::{groups::Group, Field, ToConstraintField}; use ff_fft::cfg_chunks; #[cfg(feature = "r1cs")] pub mod constraints; pub trait PedersenWindow: Clone { const WINDOW_SIZE: usize; const NUM_WINDOWS: usize; } #[derive(Clone, Default)] pub struct PedersenParameters { pub generators: Vec>, } pub struct PedersenCRH { group: PhantomData, window: PhantomData, } impl PedersenCRH { pub fn create_generators(rng: &mut R) -> Vec> { let mut generators_powers = Vec::new(); for _ in 0..W::NUM_WINDOWS { generators_powers.push(Self::generator_powers(W::WINDOW_SIZE, rng)); } generators_powers } pub fn generator_powers(num_powers: usize, rng: &mut R) -> Vec { let mut cur_gen_powers = Vec::with_capacity(num_powers); let mut base = G::rand(rng); for _ in 0..num_powers { cur_gen_powers.push(base); base.double_in_place(); } cur_gen_powers } } impl FixedLengthCRH for PedersenCRH { const INPUT_SIZE_BITS: usize = W::WINDOW_SIZE * W::NUM_WINDOWS; type Output = G; type Parameters = PedersenParameters; fn setup(rng: &mut R) -> Result { let time = start_timer!(|| format!( "PedersenCRH::Setup: {} {}-bit windows; {{0,1}}^{{{}}} -> G", W::NUM_WINDOWS, W::WINDOW_SIZE, W::NUM_WINDOWS * W::WINDOW_SIZE )); let generators = Self::create_generators(rng); end_timer!(time); Ok(Self::Parameters { generators }) } fn evaluate(parameters: &Self::Parameters, input: &[u8]) -> Result { let eval_time = start_timer!(|| "PedersenCRH::Eval"); if (input.len() * 8) > W::WINDOW_SIZE * W::NUM_WINDOWS { panic!( "incorrect input length {:?} for window params {:?}x{:?}", input.len(), W::WINDOW_SIZE, W::NUM_WINDOWS ); } let mut padded_input = Vec::with_capacity(input.len()); let mut input = input; // Pad the input if it is not the current length. 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, "Incorrect pp of size {:?}x{:?} for window params {:?}x{:?}", parameters.generators[0].len(), parameters.generators.len(), W::WINDOW_SIZE, W::NUM_WINDOWS ); // Compute sum of h_i^{m_i} for all i. let bits = bytes_to_bits(input); let result = cfg_chunks!(bits, W::WINDOW_SIZE) .zip(¶meters.generators) .map(|(bits, generator_powers)| { let mut encoded = G::zero(); for (bit, base) in bits.iter().zip(generator_powers.iter()) { if *bit { encoded += base; } } encoded }) .sum::(); end_timer!(eval_time); Ok(result) } } pub fn bytes_to_bits(bytes: &[u8]) -> Vec { let mut bits = Vec::with_capacity(bytes.len() * 8); for byte in bytes { for i in 0..8 { let bit = (*byte >> i) & 1; bits.push(bit == 1) } } bits } impl Debug for PedersenParameters { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "Pedersen Hash Parameters {{\n")?; for (i, g) in self.generators.iter().enumerate() { write!(f, "\t Generator {}: {:?}\n", i, g)?; } write!(f, "}}\n") } } impl> ToConstraintField for PedersenParameters { #[inline] fn to_field_elements(&self) -> Result, Error> { Ok(Vec::new()) } }