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::{Namespace, SynthesisError};
  2
  3use crate::{
  4    commitment::blake2s,
  5    commitment::CommitmentGadget,
  6    prf::blake2s::constraints::{evaluate_blake2s, OutputVar},
  7    Vec,
  8};
  9use algebra_core::{Field, PrimeField};
 10use r1cs_std::prelude::*;
 11
 12use core::borrow::Borrow;
 13
 14#[derive(Clone)]
 15pub struct ParametersVar;
 16
 17#[derive(Clone)]
 18pub struct RandomnessVar<F: Field>(pub Vec<UInt8<F>>);
 19
 20pub struct CommGadget;
 21
 22impl<F: PrimeField> CommitmentGadget<blake2s::Commitment, F> for CommGadget {
 23    type OutputVar = OutputVar<F>;
 24    type ParametersVar = ParametersVar;
 25    type RandomnessVar = RandomnessVar<F>;
 26
 27    #[tracing::instrument(target = "r1cs", skip(input, r))]
 28    fn commit(
 29        _: &Self::ParametersVar,
 30        input: &[UInt8<F>],
 31        r: &Self::RandomnessVar,
 32    ) -> Result<Self::OutputVar, SynthesisError> {
 33        let mut input_bits = Vec::with_capacity(512);
 34        for byte in input.iter().chain(r.0.iter()) {
 35            input_bits.extend_from_slice(&byte.to_bits_le()?);
 36        }
 37        let mut result = Vec::new();
 38        for int in evaluate_blake2s(&input_bits)?.into_iter() {
 39            let chunk = int.to_bytes()?;
 40            result.extend_from_slice(&chunk);
 41        }
 42        Ok(OutputVar(result))
 43    }
 44}
 45
 46impl<ConstraintF: Field> AllocVar<(), ConstraintF> for ParametersVar {
 47    #[tracing::instrument(target = "r1cs", skip(_cs, _f))]
 48    fn new_variable<T: Borrow<()>>(
 49        _cs: impl Into<Namespace<ConstraintF>>,
 50        _f: impl FnOnce() -> Result<T, SynthesisError>,
 51        _mode: AllocationMode,
 52    ) -> Result<Self, SynthesisError> {
 53        Ok(ParametersVar)
 54    }
 55}
 56
 57impl<ConstraintF: PrimeField> AllocVar<[u8; 32], ConstraintF> for RandomnessVar<ConstraintF> {
 58    #[tracing::instrument(target = "r1cs", skip(cs, f))]
 59    fn new_variable<T: Borrow<[u8; 32]>>(
 60        cs: impl Into<Namespace<ConstraintF>>,
 61        f: impl FnOnce() -> Result<T, SynthesisError>,
 62        mode: AllocationMode,
 63    ) -> Result<Self, SynthesisError> {
 64        let bytes = f().map(|b| *b.borrow()).unwrap_or([0u8; 32]);
 65        match mode {
 66            AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&bytes))),
 67            AllocationMode::Input => UInt8::new_input_vec(cs, &bytes).map(Self),
 68            AllocationMode::Witness => UInt8::new_witness_vec(cs, &bytes).map(Self),
 69        }
 70    }
 71}
 72
 73#[cfg(test)]
 74mod test {
 75    use crate::{
 76        commitment::blake2s::{
 77            constraints::{CommGadget, RandomnessVar},
 78            Commitment,
 79        },
 80        commitment::{CommitmentGadget, CommitmentScheme},
 81    };
 82    use algebra::{ed_on_bls12_381::Fq as Fr, test_rng};
 83    use r1cs_core::ConstraintSystem;
 84    use r1cs_std::prelude::*;
 85    use rand::Rng;
 86
 87    #[test]
 88    fn commitment_gadget_test() {
 89        let cs = ConstraintSystem::<Fr>::new_ref();
 90
 91        let input = [1u8; 32];
 92
 93        let rng = &mut test_rng();
 94
 95        type TestCOMM = Commitment;
 96        type TestCOMMGadget = CommGadget;
 97
 98        let mut randomness = [0u8; 32];
 99        rng.fill(&mut randomness);
100
101        let parameters = ();
102        let primitive_result = Commitment::commit(&parameters, &input, &randomness).unwrap();
103
104        let mut input_var = vec![];
105        for byte in &input {
106            input_var.push(UInt8::new_witness(cs.clone(), || Ok(*byte)).unwrap());
107        }
108
109        let mut randomness_var = vec![];
110        for r_byte in randomness.iter() {
111            randomness_var.push(UInt8::new_witness(cs.clone(), || Ok(r_byte)).unwrap());
112        }
113        let randomness_var = RandomnessVar(randomness_var);
114
115        let parameters_var =
116            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::ParametersVar::new_witness(
117                r1cs_core::ns!(cs, "gadget_parameters"),
118                || Ok(&parameters),
119            )
120            .unwrap();
121        let result_var = <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::commit(
122            &parameters_var,
123            &input_var,
124            &randomness_var,
125        )
126        .unwrap();
127
128        for i in 0..32 {
129            assert_eq!(primitive_result[i], result_var.0[i].value().unwrap());
130        }
131        assert!(cs.is_satisfied().unwrap());
132    }
133}