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