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