use crate::crypto_primitives::commitment::blake2s::Blake2sCommitment; use r1cs_core::{ConstraintSystem, SynthesisError}; use crate::gadgets::{ prf::blake2s::{blake2s_gadget, Blake2sOutputGadget}, CommitmentGadget, }; use algebra::{PrimeField, Field}; use r1cs_std::prelude::*; use std::borrow::Borrow; #[derive(Clone)] pub struct Blake2sParametersGadget; #[derive(Clone)] pub struct Blake2sRandomnessGadget(pub Vec); pub struct Blake2sCommitmentGadget; impl CommitmentGadget for Blake2sCommitmentGadget { type OutputGadget = Blake2sOutputGadget; type ParametersGadget = Blake2sParametersGadget; type RandomnessGadget = Blake2sRandomnessGadget; fn check_commitment_gadget>( mut cs: CS, _: &Self::ParametersGadget, input: &[UInt8], r: &Self::RandomnessGadget, ) -> Result { let mut input_bits = Vec::with_capacity(512); for byte in input.into_iter().chain(r.0.iter()) { input_bits.extend_from_slice(&byte.into_bits_le()); } let mut result = Vec::new(); for (i, int) in blake2s_gadget(cs.ns(|| "Blake2s Eval"), &input_bits)? .into_iter() .enumerate() { let chunk = int.to_bytes(&mut cs.ns(|| format!("Result ToBytes {}", i)))?; result.extend_from_slice(&chunk); } Ok(Blake2sOutputGadget(result)) } } impl AllocGadget<(), ConstraintF> for Blake2sParametersGadget { fn alloc>(_: CS, _: F) -> Result where F: FnOnce() -> Result, T: Borrow<()>, { Ok(Blake2sParametersGadget) } fn alloc_input>(_: CS, _: F) -> Result where F: FnOnce() -> Result, T: Borrow<()>, { Ok(Blake2sParametersGadget) } } impl AllocGadget<[u8; 32], ConstraintF> for Blake2sRandomnessGadget { #[inline] fn alloc>(cs: CS, value_gen: F) -> Result where F: FnOnce() -> Result, T: Borrow<[u8; 32]>, { let zeros = [0u8; 32]; let value = match value_gen() { Ok(val) => *(val.borrow()), Err(_) => zeros, }; let bytes = ::alloc_vec(cs, &value)?; Ok(Blake2sRandomnessGadget(bytes)) } #[inline] fn alloc_input>( cs: CS, value_gen: F, ) -> Result where F: FnOnce() -> Result, T: Borrow<[u8; 32]>, { let zeros = [0u8; 32]; let value = match value_gen() { Ok(val) => *(val.borrow()), Err(_) => zeros, }; let bytes = ::alloc_input_vec(cs, &value)?; Ok(Blake2sRandomnessGadget(bytes)) } } #[cfg(test)] mod test { use algebra::fields::bls12_381::Fr; use rand::{thread_rng, Rng}; use crate::{ crypto_primitives::commitment::{blake2s::Blake2sCommitment, CommitmentScheme}, gadgets::commitment::{ blake2s::{Blake2sCommitmentGadget, Blake2sRandomnessGadget}, CommitmentGadget, }, }; use r1cs_core::ConstraintSystem; use r1cs_std::prelude::*; use r1cs_std::test_constraint_system::TestConstraintSystem; #[test] fn commitment_gadget_test() { let mut cs = TestConstraintSystem::::new(); let input = [1u8; 32]; let rng = &mut thread_rng(); type TestCOMM = Blake2sCommitment; type TestCOMMGadget = Blake2sCommitmentGadget; let mut randomness = [0u8; 32]; rng.fill(&mut randomness); let parameters = (); let primitive_result = Blake2sCommitment::commit(¶meters, &input, &randomness).unwrap(); let mut input_bytes = vec![]; for (byte_i, input_byte) in input.into_iter().enumerate() { let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i)); input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap()); } let mut randomness_bytes = vec![]; for (byte_i, random_byte) in randomness.into_iter().enumerate() { let cs = cs.ns(|| format!("randomness_byte_gadget_{}", byte_i)); randomness_bytes.push(UInt8::alloc(cs, || Ok(*random_byte)).unwrap()); } let randomness_bytes = Blake2sRandomnessGadget(randomness_bytes); let gadget_parameters = >::ParametersGadget::alloc( &mut cs.ns(|| "gadget_parameters"), || Ok(¶meters), ) .unwrap(); let gadget_result = >::check_commitment_gadget( &mut cs.ns(|| "gadget_evaluation"), &gadget_parameters, &input_bytes, &randomness_bytes, ) .unwrap(); for i in 0..32 { assert_eq!(primitive_result[i], gadget_result.0[i].get_value().unwrap()); } assert!(cs.is_satisfied()); } }