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<Boolean<_>> = padded_input
 65            .iter()
 66            .flat_map(|b| b.to_bits_le().unwrap())
 67            .collect();
 68        let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
 69        let result =
 70            GG::precomputed_base_multiscalar_mul_le(&parameters.params.generators, input_in_bits)?;
 71        Ok(result)
 72    }
 73}
 74
 75impl<C, GG> AllocVar<Parameters<C>, ConstraintF<C>> for CRHParametersVar<C, GG>
 76where
 77    C: ProjectiveCurve,
 78    GG: CurveVar<C, ConstraintF<C>>,
 79    for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
 80{
 81    fn new_variable<T: Borrow<Parameters<C>>>(
 82        _cs: impl Into<Namespace<ConstraintF<C>>>,
 83        f: impl FnOnce() -> Result<T, SynthesisError>,
 84        _mode: AllocationMode,
 85    ) -> Result<Self, SynthesisError> {
 86        let params = f()?.borrow().clone();
 87        Ok(CRHParametersVar {
 88            params,
 89            _group_g: PhantomData,
 90        })
 91    }
 92}
 93
 94#[cfg(test)]
 95mod test {
 96    use crate::crh::{pedersen, pedersen::constraints::*, FixedLengthCRH, FixedLengthCRHGadget};
 97    use algebra::{
 98        ed_on_bls12_381::{EdwardsProjective as JubJub, Fq as Fr},
 99        test_rng,
100    };
101    use r1cs_core::{ConstraintSystem, ConstraintSystemRef};
102    use r1cs_std::ed_on_bls12_381::EdwardsVar;
103    use rand::Rng;
104
105    type TestCRH = pedersen::CRH<JubJub, Window>;
106    type TestCRHGadget = CRHGadget<JubJub, EdwardsVar, Window>;
107
108    #[derive(Clone, PartialEq, Eq, Hash)]
109    pub(super) struct Window;
110
111    impl pedersen::Window for Window {
112        const WINDOW_SIZE: usize = 128;
113        const NUM_WINDOWS: usize = 8;
114    }
115
116    fn generate_input<R: Rng>(
117        cs: ConstraintSystemRef<Fr>,
118        rng: &mut R,
119    ) -> ([u8; 128], Vec<UInt8<Fr>>) {
120        let mut input = [1u8; 128];
121        rng.fill_bytes(&mut input);
122
123        let mut input_bytes = vec![];
124        for byte in input.iter() {
125            input_bytes.push(UInt8::new_witness(cs.clone(), || Ok(byte)).unwrap());
126        }
127        (input, input_bytes)
128    }
129
130    #[test]
131    fn test_native_equality() {
132        let rng = &mut test_rng();
133        let cs = ConstraintSystem::<Fr>::new_ref();
134
135        let (input, input_var) = generate_input(cs.clone(), rng);
136
137        let parameters = TestCRH::setup(rng).unwrap();
138        let primitive_result = TestCRH::evaluate(&parameters, &input).unwrap();
139
140        let parameters_var =
141            CRHParametersVar::new_constant(cs.ns("CRH Parameters"), &parameters).unwrap();
142
143        let result_var = TestCRHGadget::evaluate(&parameters_var, &input_var).unwrap();
144
145        let primitive_result = primitive_result;
146        assert_eq!(primitive_result, result_var.value().unwrap());
147        assert!(cs.is_satisfied().unwrap());
148    }
149}