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