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