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