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<F, T, CS: ConstraintSystem<ConstraintF>>(
 93        _cs: CS,
 94        value_gen: F,
 95    ) -> Result<Self, SynthesisError>
 96    where
 97        F: FnOnce() -> Result<T, SynthesisError>,
 98        T: Borrow<BoweHopwoodPedersenParameters<G>>,
 99    {
100        let params = value_gen()?.borrow().clone();
101        Ok(BoweHopwoodPedersenCRHGadgetParameters {
102            params,
103            _group_g: PhantomData,
104            _engine: PhantomData,
105            _window: PhantomData,
106        })
107    }
108
109    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
110        _cs: CS,
111        value_gen: F,
112    ) -> Result<Self, SynthesisError>
113    where
114        F: FnOnce() -> Result<T, SynthesisError>,
115        T: Borrow<BoweHopwoodPedersenParameters<G>>,
116    {
117        let params = value_gen()?.borrow().clone();
118        Ok(BoweHopwoodPedersenCRHGadgetParameters {
119            params,
120            _group_g: PhantomData,
121            _engine: PhantomData,
122            _window: PhantomData,
123        })
124    }
125}
126
127#[cfg(test)]
128mod test {
129    use rand::Rng;
130
131    use crate::crh::{
132        bowe_hopwood::{constraints::BoweHopwoodPedersenCRHGadget, BoweHopwoodPedersenCRH},
133        pedersen::PedersenWindow,
134        FixedLengthCRH, FixedLengthCRHGadget,
135    };
136    use algebra::{
137        jubjub::{Fq as Fr, JubJubProjective as JubJub},
138        test_rng, ProjectiveCurve,
139    };
140    use r1cs_core::ConstraintSystem;
141    use r1cs_std::{
142        alloc::AllocGadget, jubjub::JubJubGadget, test_constraint_system::TestConstraintSystem,
143        uint8::UInt8,
144    };
145
146    type TestCRH = BoweHopwoodPedersenCRH<JubJub, Window>;
147    type TestCRHGadget = BoweHopwoodPedersenCRHGadget<JubJub, Fr, JubJubGadget>;
148
149    #[derive(Clone, PartialEq, Eq, Hash)]
150    pub(super) struct Window;
151
152    impl PedersenWindow for Window {
153        const WINDOW_SIZE: usize = 63;
154        const NUM_WINDOWS: usize = 8;
155    }
156
157    fn generate_input<CS: ConstraintSystem<Fr>, R: Rng>(
158        mut cs: CS,
159        rng: &mut R,
160    ) -> ([u8; 189], Vec<UInt8>) {
161        let mut input = [1u8; 189];
162        rng.fill_bytes(&mut input);
163
164        let mut input_bytes = vec![];
165        for (byte_i, input_byte) in input.iter().enumerate() {
166            let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i));
167            input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap());
168        }
169        (input, input_bytes)
170    }
171
172    #[test]
173    fn crh_primitive_gadget_test() {
174        let rng = &mut test_rng();
175        let mut cs = TestConstraintSystem::<Fr>::new();
176
177        let (input, input_bytes) = generate_input(&mut cs, rng);
178        println!("number of constraints for input: {}", cs.num_constraints());
179
180        let parameters = TestCRH::setup(rng).unwrap();
181        let primitive_result = TestCRH::evaluate(&parameters, &input).unwrap();
182
183        let gadget_parameters =
184            <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::ParametersGadget::alloc(
185                &mut cs.ns(|| "gadget_parameters"),
186                || Ok(&parameters),
187            )
188            .unwrap();
189        println!(
190            "number of constraints for input + params: {}",
191            cs.num_constraints()
192        );
193
194        let gadget_result =
195            <TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::check_evaluation_gadget(
196                &mut cs.ns(|| "gadget_evaluation"),
197                &gadget_parameters,
198                &input_bytes,
199            )
200            .unwrap();
201
202        println!("number of constraints total: {}", cs.num_constraints());
203
204        let primitive_result = primitive_result.into_affine();
205        assert_eq!(primitive_result.x, gadget_result.x.value.unwrap());
206        assert_eq!(primitive_result.y, gadget_result.y.value.unwrap());
207        assert!(cs.is_satisfied());
208    }
209}