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