use r1cs_core::{Namespace, SynthesisError}; use crate::{ commitment::blake2s, commitment::CommitmentGadget, prf::blake2s::constraints::{evaluate_blake2s, OutputVar}, Vec, }; use algebra_core::{Field, PrimeField}; use r1cs_std::prelude::*; use core::borrow::Borrow; #[derive(Clone)] pub struct ParametersVar; #[derive(Clone)] pub struct RandomnessVar(pub Vec>); pub struct CommGadget; impl CommitmentGadget for CommGadget { type OutputVar = OutputVar; type ParametersVar = ParametersVar; type RandomnessVar = RandomnessVar; fn commit( _: &Self::ParametersVar, input: &[UInt8], r: &Self::RandomnessVar, ) -> Result { let mut input_bits = Vec::with_capacity(512); for byte in input.iter().chain(r.0.iter()) { input_bits.extend_from_slice(&byte.to_bits_le()?); } let mut result = Vec::new(); for int in evaluate_blake2s(&input_bits)?.into_iter() { let chunk = int.to_bytes()?; result.extend_from_slice(&chunk); } Ok(OutputVar(result)) } } impl AllocVar<(), ConstraintF> for ParametersVar { fn new_variable>( _cs: impl Into>, _f: impl FnOnce() -> Result, _mode: AllocationMode, ) -> Result { Ok(ParametersVar) } } impl AllocVar<[u8; 32], ConstraintF> for RandomnessVar { fn new_variable>( cs: impl Into>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result { let bytes = f().map(|b| *b.borrow()).unwrap_or([0u8; 32]); match mode { AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&bytes))), AllocationMode::Input => UInt8::new_input_vec(cs, &bytes).map(Self), AllocationMode::Witness => UInt8::new_witness_vec(cs, &bytes).map(Self), } } } #[cfg(test)] mod test { use crate::{ commitment::blake2s::{ constraints::{CommGadget, RandomnessVar}, Commitment, }, commitment::{CommitmentGadget, CommitmentScheme}, }; use algebra::{ed_on_bls12_381::Fq as Fr, test_rng}; use r1cs_core::ConstraintSystem; use r1cs_std::prelude::*; use rand::Rng; #[test] fn commitment_gadget_test() { let cs = ConstraintSystem::::new_ref(); let input = [1u8; 32]; let rng = &mut test_rng(); type TestCOMM = Commitment; type TestCOMMGadget = CommGadget; let mut randomness = [0u8; 32]; rng.fill(&mut randomness); let parameters = (); let primitive_result = Commitment::commit(¶meters, &input, &randomness).unwrap(); let mut input_var = vec![]; for byte in &input { input_var.push(UInt8::new_witness(cs.clone(), || Ok(*byte)).unwrap()); } let mut randomness_var = vec![]; for r_byte in randomness.iter() { randomness_var.push(UInt8::new_witness(cs.clone(), || Ok(r_byte)).unwrap()); } let randomness_var = RandomnessVar(randomness_var); let parameters_var = >::ParametersVar::new_witness( cs.ns("gadget_parameters"), || Ok(¶meters), ) .unwrap(); let result_var = >::commit( ¶meters_var, &input_var, &randomness_var, ) .unwrap(); for i in 0..32 { assert_eq!(primitive_result[i], result_var.0[i].value().unwrap()); } assert!(cs.is_satisfied().unwrap()); } }