arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/crypto-primitives/src/crh/pedersen/constraints.rs
crypto-primitives/src/crh/pedersen/constraints.rsRaw
  1use crate::{
  2    crh::{
  3        pedersen::{Parameters, Window, CRH},
  4        FixedLengthCRHGadget,
  5    },
  6    Vec,
  7};
  8use algebra_core::{Field, ProjectiveCurve};
  9use r1cs_core::{Namespace, SynthesisError};
 10use r1cs_std::prelude::*;
 11
 12use core::{borrow::Borrow, marker::PhantomData};
 13
 14#[derive(Derivative)]
 15#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))]
 16pub struct CRHParametersVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>>
 17where
 18    for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
 19{
 20    params: Parameters<C>,
 21    #[doc(hidden)]
 22    _group_g: PhantomData<GG>,
 23}
 24
 25type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField;
 26pub struct CRHGadget<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>, W: Window>
 27where
 28    for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
 29{
 30    #[doc(hidden)]
 31    _group: PhantomData<*const C>,
 32    #[doc(hidden)]
 33    _group_var: PhantomData<*const GG>,
 34    #[doc(hidden)]
 35    _window: PhantomData<*const W>,
 36}
 37
 38impl<C, GG, W> FixedLengthCRHGadget<CRH<C, W>, ConstraintF<C>> for CRHGadget<C, GG, W>
 39where
 40    C: ProjectiveCurve,
 41    GG: CurveVar<C, ConstraintF<C>>,
 42    W: Window,
 43    for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
 44{
 45    type OutputVar = GG;
 46    type ParametersVar = CRHParametersVar<C, GG>;
 47
 48    fn evaluate(
 49        parameters: &Self::ParametersVar,
 50        input: &[UInt8<ConstraintF<C>>],
 51    ) -> Result<Self::OutputVar, SynthesisError> {
 52        let mut padded_input = input.to_vec();
 53        // Pad the input if it is not the current length.
 54        if input.len() * 8 < W::WINDOW_SIZE * W::NUM_WINDOWS {
 55            let current_length = input.len();
 56            for _ in current_length..(W::WINDOW_SIZE * W::NUM_WINDOWS / 8) {
 57                padded_input.push(UInt8::constant(0u8));
 58            }
 59        }
 60        assert_eq!(padded_input.len() * 8, W::WINDOW_SIZE * W::NUM_WINDOWS);
 61        assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS);
 62
 63        // Allocate new variable for the result.
 64        let input_in_bits: Vec<_> = padded_input.iter().flat_map(|b| b.into_bits_le()).collect();
 65        let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
 66        let result =
 67            GG::precomputed_base_multiscalar_mul(&parameters.params.generators, input_in_bits)?;
 68
 69        Ok(result)
 70    }
 71}
 72
 73impl<C, GG> AllocVar<Parameters<C>, ConstraintF<C>> for CRHParametersVar<C, GG>
 74where
 75    C: ProjectiveCurve,
 76    GG: CurveVar<C, ConstraintF<C>>,
 77    for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
 78{
 79    fn new_variable<T: Borrow<Parameters<C>>>(
 80        _cs: impl Into<Namespace<ConstraintF<C>>>,
 81        f: impl FnOnce() -> Result<T, SynthesisError>,
 82        _mode: AllocationMode,
 83    ) -> Result<Self, SynthesisError> {
 84        let params = f()?.borrow().clone();
 85        Ok(CRHParametersVar {
 86            params,
 87            _group_g: PhantomData,
 88        })
 89    }
 90}
 91
 92#[cfg(test)]
 93mod test {
 94    use crate::crh::{pedersen, pedersen::constraints::*, FixedLengthCRH, FixedLengthCRHGadget};
 95    use algebra::{
 96        ed_on_bls12_381::{EdwardsProjective as JubJub, Fq as Fr},
 97        test_rng,
 98    };
 99    use r1cs_core::{ConstraintSystem, ConstraintSystemRef};
100    use r1cs_std::ed_on_bls12_381::EdwardsVar;
101    use rand::Rng;
102
103    type TestCRH = pedersen::CRH<JubJub, Window>;
104    type TestCRHGadget = CRHGadget<JubJub, EdwardsVar, Window>;
105
106    #[derive(Clone, PartialEq, Eq, Hash)]
107    pub(super) struct Window;
108
109    impl pedersen::Window for Window {
110        const WINDOW_SIZE: usize = 128;
111        const NUM_WINDOWS: usize = 8;
112    }
113
114    fn generate_input<R: Rng>(
115        cs: ConstraintSystemRef<Fr>,
116        rng: &mut R,
117    ) -> ([u8; 128], Vec<UInt8<Fr>>) {
118        let mut input = [1u8; 128];
119        rng.fill_bytes(&mut input);
120
121        let mut input_bytes = vec![];
122        for byte in input.iter() {
123            input_bytes.push(UInt8::new_witness(cs.clone(), || Ok(byte)).unwrap());
124        }
125        (input, input_bytes)
126    }
127
128    #[test]
129    fn test_native_equality() {
130        let rng = &mut test_rng();
131        let cs = ConstraintSystem::<Fr>::new_ref();
132
133        let (input, input_var) = generate_input(cs.clone(), rng);
134
135        let parameters = TestCRH::setup(rng).unwrap();
136        let primitive_result = TestCRH::evaluate(&parameters, &input).unwrap();
137
138        let parameters_var =
139            CRHParametersVar::new_constant(cs.ns("CRH Parameters"), &parameters).unwrap();
140
141        let result_var = TestCRHGadget::evaluate(&parameters_var, &input_var).unwrap();
142
143        let primitive_result = primitive_result;
144        assert_eq!(primitive_result, result_var.value().unwrap());
145        assert!(cs.is_satisfied().unwrap());
146    }
147}