arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/crypto-primitives/src/commitment/blake2s/constraints.rs
crypto-primitives/src/commitment/blake2s/constraints.rsRaw
  1use r1cs_core::{ConstraintSystem, SynthesisError};
  2
  3use crate::{
  4    commitment::blake2s::Blake2sCommitment,
  5    prf::blake2s::constraints::{blake2s_gadget, Blake2sOutputGadget},
  6    CommitmentGadget, Vec,
  7};
  8use algebra_core::{Field, PrimeField};
  9use r1cs_std::prelude::*;
 10
 11use core::borrow::Borrow;
 12
 13#[derive(Clone)]
 14pub struct Blake2sParametersGadget;
 15
 16#[derive(Clone)]
 17pub struct Blake2sRandomnessGadget(pub Vec<UInt8>);
 18
 19pub struct Blake2sCommitmentGadget;
 20
 21impl<ConstraintF: PrimeField> CommitmentGadget<Blake2sCommitment, ConstraintF>
 22    for Blake2sCommitmentGadget
 23{
 24    type OutputGadget = Blake2sOutputGadget;
 25    type ParametersGadget = Blake2sParametersGadget;
 26    type RandomnessGadget = Blake2sRandomnessGadget;
 27
 28    fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>(
 29        mut cs: CS,
 30        _: &Self::ParametersGadget,
 31        input: &[UInt8],
 32        r: &Self::RandomnessGadget,
 33    ) -> Result<Self::OutputGadget, SynthesisError> {
 34        let mut input_bits = Vec::with_capacity(512);
 35        for byte in input.iter().chain(r.0.iter()) {
 36            input_bits.extend_from_slice(&byte.into_bits_le());
 37        }
 38        let mut result = Vec::new();
 39        for (i, int) in blake2s_gadget(cs.ns(|| "Blake2s Eval"), &input_bits)?
 40            .into_iter()
 41            .enumerate()
 42        {
 43            let chunk = int.to_bytes(&mut cs.ns(|| format!("Result ToBytes {}", i)))?;
 44            result.extend_from_slice(&chunk);
 45        }
 46        Ok(Blake2sOutputGadget(result))
 47    }
 48}
 49
 50impl<ConstraintF: Field> AllocGadget<(), ConstraintF> for Blake2sParametersGadget {
 51    fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(_: CS, _: F) -> Result<Self, SynthesisError>
 52    where
 53        F: FnOnce() -> Result<T, SynthesisError>,
 54        T: Borrow<()>,
 55    {
 56        Ok(Blake2sParametersGadget)
 57    }
 58
 59    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
 60        _: CS,
 61        _: F,
 62    ) -> Result<Self, SynthesisError>
 63    where
 64        F: FnOnce() -> Result<T, SynthesisError>,
 65        T: Borrow<()>,
 66    {
 67        Ok(Blake2sParametersGadget)
 68    }
 69}
 70
 71impl<ConstraintF: PrimeField> AllocGadget<[u8; 32], ConstraintF> for Blake2sRandomnessGadget {
 72    #[inline]
 73    fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
 74        cs: CS,
 75        value_gen: F,
 76    ) -> Result<Self, SynthesisError>
 77    where
 78        F: FnOnce() -> Result<T, SynthesisError>,
 79        T: Borrow<[u8; 32]>,
 80    {
 81        let zeros = [0u8; 32];
 82        let value = match value_gen() {
 83            Ok(val) => *(val.borrow()),
 84            Err(_) => zeros,
 85        };
 86        let bytes = <UInt8>::alloc_vec(cs, &value)?;
 87
 88        Ok(Blake2sRandomnessGadget(bytes))
 89    }
 90
 91    #[inline]
 92    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
 93        cs: CS,
 94        value_gen: F,
 95    ) -> Result<Self, SynthesisError>
 96    where
 97        F: FnOnce() -> Result<T, SynthesisError>,
 98        T: Borrow<[u8; 32]>,
 99    {
100        let zeros = [0u8; 32];
101        let value = match value_gen() {
102            Ok(val) => *(val.borrow()),
103            Err(_) => zeros,
104        };
105        let bytes = <UInt8>::alloc_input_vec(cs, &value)?;
106
107        Ok(Blake2sRandomnessGadget(bytes))
108    }
109}
110
111#[cfg(test)]
112mod test {
113    use crate::{
114        commitment::blake2s::{
115            constraints::{Blake2sCommitmentGadget, Blake2sRandomnessGadget},
116            Blake2sCommitment,
117        },
118        *,
119    };
120    use algebra::{jubjub::Fq as Fr, test_rng};
121    use r1cs_core::ConstraintSystem;
122    use r1cs_std::{prelude::*, test_constraint_system::TestConstraintSystem};
123    use rand::Rng;
124
125    #[test]
126    fn commitment_gadget_test() {
127        let mut cs = TestConstraintSystem::<Fr>::new();
128
129        let input = [1u8; 32];
130
131        let rng = &mut test_rng();
132
133        type TestCOMM = Blake2sCommitment;
134        type TestCOMMGadget = Blake2sCommitmentGadget;
135
136        let mut randomness = [0u8; 32];
137        rng.fill(&mut randomness);
138
139        let parameters = ();
140        let primitive_result = Blake2sCommitment::commit(&parameters, &input, &randomness).unwrap();
141
142        let mut input_bytes = vec![];
143        for (byte_i, input_byte) in input.iter().enumerate() {
144            let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i));
145            input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap());
146        }
147
148        let mut randomness_bytes = vec![];
149        for (byte_i, random_byte) in randomness.iter().enumerate() {
150            let cs = cs.ns(|| format!("randomness_byte_gadget_{}", byte_i));
151            randomness_bytes.push(UInt8::alloc(cs, || Ok(*random_byte)).unwrap());
152        }
153        let randomness_bytes = Blake2sRandomnessGadget(randomness_bytes);
154
155        let gadget_parameters =
156            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::ParametersGadget::alloc(
157                &mut cs.ns(|| "gadget_parameters"),
158                || Ok(&parameters),
159            )
160            .unwrap();
161        let gadget_result =
162            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::check_commitment_gadget(
163                &mut cs.ns(|| "gadget_evaluation"),
164                &gadget_parameters,
165                &input_bytes,
166                &randomness_bytes,
167            )
168            .unwrap();
169
170        for i in 0..32 {
171            assert_eq!(primitive_result[i], gadget_result.0[i].get_value().unwrap());
172        }
173        assert!(cs.is_satisfied());
174    }
175}