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