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::crh::{
  2    pedersen::{PedersenCRH, PedersenParameters, PedersenWindow},
  3    FixedLengthCRHGadget,
  4};
  5use algebra_core::{Field, Group};
  6use r1cs_core::{ConstraintSystem, SynthesisError};
  7use r1cs_std::prelude::*;
  8
  9use core::{borrow::Borrow, marker::PhantomData};
 10
 11#[derive(Derivative)]
 12#[derivative(Clone(
 13    bound = "G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>"
 14))]
 15pub struct PedersenCRHGadgetParameters<
 16    G: Group,
 17    W: PedersenWindow,
 18    ConstraintF: Field,
 19    GG: GroupGadget<G, ConstraintF>,
 20> {
 21    params:   PedersenParameters<G>,
 22    _group_g: PhantomData<GG>,
 23    _engine:  PhantomData<ConstraintF>,
 24    _window:  PhantomData<W>,
 25}
 26
 27pub struct PedersenCRHGadget<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> {
 28    #[doc(hideen)]
 29    _group:        PhantomData<*const G>,
 30    #[doc(hideen)]
 31    _group_gadget: PhantomData<*const GG>,
 32    #[doc(hideen)]
 33    _engine:       PhantomData<ConstraintF>,
 34}
 35
 36impl<ConstraintF, G, GG, W> FixedLengthCRHGadget<PedersenCRH<G, W>, ConstraintF>
 37    for PedersenCRHGadget<G, ConstraintF, GG>
 38where
 39    ConstraintF: Field,
 40    G: Group,
 41    GG: GroupGadget<G, ConstraintF>,
 42    W: PedersenWindow,
 43{
 44    type OutputGadget = GG;
 45    type ParametersGadget = PedersenCRHGadgetParameters<G, W, ConstraintF, GG>;
 46
 47    fn check_evaluation_gadget<CS: ConstraintSystem<ConstraintF>>(
 48        cs: CS,
 49        parameters: &Self::ParametersGadget,
 50        input: &[UInt8],
 51    ) -> Result<Self::OutputGadget, 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
 65            .iter()
 66            .flat_map(|byte| byte.into_bits_le())
 67            .collect();
 68        let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
 69        let result =
 70            GG::precomputed_base_multiscalar_mul(cs, &parameters.params.generators, input_in_bits)?;
 71
 72        Ok(result)
 73    }
 74}
 75
 76impl<G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>>
 77    AllocGadget<PedersenParameters<G>, ConstraintF>
 78    for PedersenCRHGadgetParameters<G, W, ConstraintF, GG>
 79{
 80    fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
 81        _cs: CS,
 82        value_gen: F,
 83    ) -> Result<Self, SynthesisError>
 84    where
 85        F: FnOnce() -> Result<T, SynthesisError>,
 86        T: Borrow<PedersenParameters<G>>,
 87    {
 88        let params = value_gen()?.borrow().clone();
 89        Ok(PedersenCRHGadgetParameters {
 90            params,
 91            _group_g: PhantomData,
 92            _engine: PhantomData,
 93            _window: PhantomData,
 94        })
 95    }
 96
 97    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
 98        _cs: CS,
 99        value_gen: F,
100    ) -> Result<Self, SynthesisError>
101    where
102        F: FnOnce() -> Result<T, SynthesisError>,
103        T: Borrow<PedersenParameters<G>>,
104    {
105        let params = value_gen()?.borrow().clone();
106        Ok(PedersenCRHGadgetParameters {
107            params,
108            _group_g: PhantomData,
109            _engine: PhantomData,
110            _window: PhantomData,
111        })
112    }
113}
114
115#[cfg(test)]
116mod test {
117    use crate::crh::{
118        pedersen::{constraints::PedersenCRHGadget, PedersenCRH, PedersenWindow},
119        FixedLengthCRH, FixedLengthCRHGadget,
120    };
121    use algebra::{
122        jubjub::{Fq as Fr, JubJubProjective as JubJub},
123        test_rng, ProjectiveCurve,
124    };
125    use r1cs_core::ConstraintSystem;
126    use r1cs_std::{
127        jubjub::JubJubGadget, prelude::*, test_constraint_system::TestConstraintSystem,
128    };
129    use rand::Rng;
130
131    type TestCRH = PedersenCRH<JubJub, Window>;
132    type TestCRHGadget = PedersenCRHGadget<JubJub, Fr, JubJubGadget>;
133
134    #[derive(Clone, PartialEq, Eq, Hash)]
135    pub(super) struct Window;
136
137    impl PedersenWindow for Window {
138        const WINDOW_SIZE: usize = 128;
139        const NUM_WINDOWS: usize = 8;
140    }
141
142    fn generate_input<CS: ConstraintSystem<Fr>, R: Rng>(
143        mut cs: CS,
144        rng: &mut R,
145    ) -> ([u8; 128], Vec<UInt8>) {
146        let mut input = [1u8; 128];
147        rng.fill_bytes(&mut input);
148
149        let mut input_bytes = vec![];
150        for (byte_i, input_byte) in input.iter().enumerate() {
151            let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i));
152            input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap());
153        }
154        (input, input_bytes)
155    }
156
157    #[test]
158    fn crh_primitive_gadget_test() {
159        let rng = &mut test_rng();
160        let mut cs = TestConstraintSystem::<Fr>::new();
161
162        let (input, input_bytes) = generate_input(&mut cs, rng);
163        println!("number of constraints for input: {}", cs.num_constraints());
164
165        let parameters = TestCRH::setup(rng).unwrap();
166        let primitive_result = TestCRH::evaluate(&parameters, &input).unwrap();
167
168        let gadget_parameters =
169            <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::ParametersGadget::alloc(
170                &mut cs.ns(|| "gadget_parameters"),
171                || Ok(&parameters),
172            )
173            .unwrap();
174        println!(
175            "number of constraints for input + params: {}",
176            cs.num_constraints()
177        );
178
179        let gadget_result =
180            <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::check_evaluation_gadget(
181                &mut cs.ns(|| "gadget_evaluation"),
182                &gadget_parameters,
183                &input_bytes,
184            )
185            .unwrap();
186
187        println!("number of constraints total: {}", cs.num_constraints());
188
189        let primitive_result = primitive_result.into_affine();
190        assert_eq!(primitive_result.x, gadget_result.x.value.unwrap());
191        assert_eq!(primitive_result.y, gadget_result.y.value.unwrap());
192        assert!(cs.is_satisfied());
193    }
194}