arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/r1cs-std/src/fields/fp2.rs
r1cs-std/src/fields/fp2.rsRaw
  1use algebra::{
  2    fields::{Fp2, Fp2Parameters},
  3    Field, PrimeField,
  4};
  5use r1cs_core::{ConstraintSystem, SynthesisError};
  6use std::{borrow::Borrow, marker::PhantomData};
  7
  8use crate::fields::fp::FpGadget;
  9use crate::prelude::*;
 10use crate::{Assignment, ConstraintVar};
 11
 12#[derive(Derivative)]
 13#[derivative(Debug(bound = "P: Fp2Parameters, ConstraintF: PrimeField"))]
 14#[must_use]
 15pub struct Fp2Gadget<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> {
 16    pub c0: FpGadget<ConstraintF>,
 17    pub c1: FpGadget<ConstraintF>,
 18    #[derivative(Debug = "ignore")]
 19    _params: PhantomData<P>,
 20}
 21
 22impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> Fp2Gadget<P, ConstraintF> {
 23    pub fn new(c0: FpGadget<ConstraintF>, c1: FpGadget<ConstraintF>) -> Self {
 24        Self {
 25            c0,
 26            c1,
 27            _params: PhantomData,
 28        }
 29    }
 30
 31    /// Multiply a FpGadget by quadratic nonresidue P::NONRESIDUE.
 32    #[inline]
 33    pub fn mul_fp_gadget_by_nonresidue<CS: ConstraintSystem<ConstraintF>>(
 34        cs: CS,
 35        fe: &FpGadget<ConstraintF>,
 36    ) -> Result<FpGadget<ConstraintF>, SynthesisError> {
 37        fe.mul_by_constant(cs, &P::NONRESIDUE)
 38    }
 39
 40    /// Multiply a Fp2Gadget by an element of fp.
 41    #[inline]
 42    pub fn mul_by_fp_constant_in_place<CS: ConstraintSystem<ConstraintF>>(
 43        &mut self,
 44        mut cs: CS,
 45        fe: &P::Fp,
 46    ) -> Result<&mut Self, SynthesisError> {
 47        self.c0.mul_by_constant_in_place(cs.ns(|| "c0"), fe)?;
 48        self.c1.mul_by_constant_in_place(cs.ns(|| "c1"), fe)?;
 49        Ok(self)
 50    }
 51
 52    /// Multiply a Fp2Gadget by an element of fp.
 53    #[inline]
 54    pub fn mul_by_fp_constant<CS: ConstraintSystem<ConstraintF>>(
 55        &self,
 56        cs: CS,
 57        fe: &P::Fp,
 58    ) -> Result<Self, SynthesisError> {
 59        let mut result = self.clone();
 60        result.mul_by_fp_constant_in_place(cs, fe)?;
 61        Ok(result)
 62    }
 63}
 64
 65impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> FieldGadget<Fp2<P>, ConstraintF> for Fp2Gadget<P, ConstraintF> {
 66    type Variable = (ConstraintVar<ConstraintF>, ConstraintVar<ConstraintF>);
 67
 68    #[inline]
 69    fn get_value(&self) -> Option<Fp2<P>> {
 70        match (self.c0.value, self.c1.value) {
 71            (Some(c0), Some(c1)) => Some(Fp2::new(c0, c1)),
 72            (..) => None,
 73        }
 74    }
 75
 76    #[inline]
 77    fn get_variable(&self) -> Self::Variable {
 78        (
 79            self.c0.get_variable().clone(),
 80            self.c1.get_variable().clone(),
 81        )
 82    }
 83
 84    #[inline]
 85    fn zero<CS: ConstraintSystem<ConstraintF>>(mut cs: CS) -> Result<Self, SynthesisError> {
 86        let c0 = FpGadget::zero(cs.ns(|| "c0"))?;
 87        let c1 = FpGadget::zero(cs.ns(|| "c1"))?;
 88        Ok(Self::new(c0, c1))
 89    }
 90
 91    #[inline]
 92    fn one<CS: ConstraintSystem<ConstraintF>>(mut cs: CS) -> Result<Self, SynthesisError> {
 93        let c0 = FpGadget::one(cs.ns(|| "c0"))?;
 94        let c1 = FpGadget::zero(cs.ns(|| "c1"))?;
 95        Ok(Self::new(c0, c1))
 96    }
 97
 98    #[inline]
 99    fn add<CS: ConstraintSystem<ConstraintF>>(
100        &self,
101        mut cs: CS,
102        other: &Self,
103    ) -> Result<Self, SynthesisError> {
104        let c0 = self.c0.add(&mut cs.ns(|| "add c0"), &other.c0)?;
105        let c1 = self.c1.add(&mut cs.ns(|| "add c1"), &other.c1)?;
106        Ok(Self::new(c0, c1))
107    }
108
109    #[inline]
110    fn sub<CS: ConstraintSystem<ConstraintF>>(
111        &self,
112        mut cs: CS,
113        other: &Self,
114    ) -> Result<Self, SynthesisError> {
115        let c0 = self.c0.sub(&mut cs.ns(|| "sub c0"), &other.c0)?;
116        let c1 = self.c1.sub(&mut cs.ns(|| "sub c1"), &other.c1)?;
117        Ok(Self::new(c0, c1))
118    }
119
120    #[inline]
121    fn double<CS: ConstraintSystem<ConstraintF>>(&self, cs: CS) -> Result<Self, SynthesisError> {
122        let mut result = self.clone();
123        result.double_in_place(cs)?;
124        Ok(result)
125    }
126
127    #[inline]
128    fn double_in_place<CS: ConstraintSystem<ConstraintF>>(
129        &mut self,
130        mut cs: CS,
131    ) -> Result<&mut Self, SynthesisError> {
132        self.c0.double_in_place(&mut cs.ns(|| "double c0"))?;
133        self.c1.double_in_place(&mut cs.ns(|| "double c1"))?;
134        Ok(self)
135    }
136
137    #[inline]
138    fn negate<CS: ConstraintSystem<ConstraintF>>(&self, cs: CS) -> Result<Self, SynthesisError> {
139        let mut result = self.clone();
140        result.negate_in_place(cs)?;
141        Ok(result)
142    }
143
144    #[inline]
145    fn negate_in_place<CS: ConstraintSystem<ConstraintF>>(
146        &mut self,
147        mut cs: CS,
148    ) -> Result<&mut Self, SynthesisError> {
149        self.c0.negate_in_place(&mut cs.ns(|| "negate c0"))?;
150        self.c1.negate_in_place(&mut cs.ns(|| "negate c1"))?;
151        Ok(self)
152    }
153
154    #[inline]
155    fn mul<CS: ConstraintSystem<ConstraintF>>(
156        &self,
157        mut cs: CS,
158        other: &Self,
159    ) -> Result<Self, SynthesisError> {
160        // Karatsuba multiplication for Fp2:
161        //     v0 = A.c0 * B.c0
162        //     v1 = A.c1 * B.c1
163        //     result.c0 = v0 + non_residue * v1
164        //     result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1
165        // Enforced with 3 constraints:
166        //     A.c1 * B.c1 = v1
167        //     A.c0 * B.c0 = result.c0 - non_residue * v1
168        //     (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + result.c0 + (1 - non_residue) * v1
169        // Reference:
170        // "Multiplication and Squaring on Pairing-Friendly Fields"
171        // Devegili, OhEigeartaigh, Scott, Dahab
172        let mul_cs = &mut cs.ns(|| "mul");
173
174        let v0 = self.c0.mul(mul_cs.ns(|| "v0"), &other.c0)?;
175        let v1 = self.c1.mul(mul_cs.ns(|| "v1"), &other.c1)?;
176        let c0 = {
177            let non_residue_times_v1 =
178                v1.mul_by_constant(mul_cs.ns(|| "non_residue * v0"), &P::NONRESIDUE)?;
179            v0.add(mul_cs.ns(|| "v0 + beta * v1"), &non_residue_times_v1)?
180        };
181        let c1 = {
182            let a0_plus_a1 = self.c0.add(mul_cs.ns(|| "a0 + a1"), &self.c1)?;
183            let b0_plus_b1 = other.c0.add(mul_cs.ns(|| "b0 + b1"), &other.c1)?;
184            let a0_plus_a1_times_b0_plus_b1 =
185                a0_plus_a1.mul(&mut mul_cs.ns(|| "(a0 + a1) * (b0 + b1)"), &b0_plus_b1)?;
186            a0_plus_a1_times_b0_plus_b1
187                .sub(mul_cs.ns(|| "res - v0"), &v0)?
188                .sub(mul_cs.ns(|| "res - v0 - v1"), &v1)?
189        };
190        Ok(Self::new(c0, c1))
191    }
192
193    #[inline]
194    fn square<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> {
195        // From Libsnark/fp2_gadget.tcc
196        // Complex multiplication for Fp2:
197        //     v0 = A.c0 * A.c1
198        //     result.c0 = (A.c0 + A.c1) * (A.c0 + non_residue * A.c1) - (1 +
199        // non_residue) * v0     result.c1 = 2 * v0
200        // Enforced with 2 constraints:
201        //     (2*A.c0) * A.c1 = result.c1
202        //     (A.c0 + A.c1) * (A.c0 + non_residue * A.c1) = result.c0 + result.c1 * (1
203        // + non_residue)/2 Reference:
204        //     "Multiplication and Squaring on Pairing-Friendly Fields"
205        //     Devegili, OhEigeartaigh, Scott, Dahab
206
207        let mut v0 = self.c0.mul(cs.ns(|| "v0"), &self.c1)?;
208        let a0_plus_a1 = self.c0.add(cs.ns(|| "a0 + a1"), &self.c1)?;
209
210        let non_residue_c1 = self
211            .c1
212            .mul_by_constant(cs.ns(|| "non_residue * a1"), &P::NONRESIDUE)?;
213        let a0_plus_non_residue_c1 = self
214            .c0
215            .add(cs.ns(|| "a0 + non_residue * a1"), &non_residue_c1)?;
216        let one_plus_non_residue_v0 = v0.mul_by_constant(
217            cs.ns(|| "1 + non_residue * v0"),
218            &(P::Fp::one() + &P::NONRESIDUE),
219        )?;
220
221        let c0 = a0_plus_a1
222            .mul(
223                cs.ns(|| "(a0 + a1) * (a0 + non_residue * a1)"),
224                &a0_plus_non_residue_c1,
225            )?
226            .sub(cs.ns(|| "- (1 + non_residue) v0"), &one_plus_non_residue_v0)?;
227
228        v0.double_in_place(cs.ns(|| "2v0"))?;
229        let c1 = v0;
230
231        Ok(Self::new(c0, c1))
232    }
233
234    #[inline]
235    fn square_in_place<CS: ConstraintSystem<ConstraintF>>(
236        &mut self,
237        mut cs: CS,
238    ) -> Result<&mut Self, SynthesisError> {
239        // From Libsnark/fp2_gadget.tcc
240        // Complex multiplication for Fp2:
241        //     v0 = A.c0 * A.c1
242        //     result.c0 = (A.c0 + A.c1) * (A.c0 + non_residue * A.c1) - (1 +
243        // non_residue) * v0     result.c1 = 2 * v0
244        // Enforced with 2 constraints:
245        //     (2*A.c0) * A.c1 = result.c1
246        //     (A.c0 + A.c1) * (A.c0 + non_residue * A.c1) = result.c0 + result.c1 * (1
247        // + non_residue)/2 Reference:
248        //     "Multiplication and Squaring on Pairing-Friendly Fields"
249        //     Devegili, OhEigeartaigh, Scott, Dahab
250
251        let mut v0 = self.c0.mul(cs.ns(|| "v0"), &self.c1)?;
252        let a0_plus_a1 = self.c0.add(cs.ns(|| "a0 + a1"), &self.c1)?;
253
254        let _ = self
255            .c1
256            .mul_by_constant_in_place(cs.ns(|| "non_residue * a1"), &P::NONRESIDUE)?;
257        let a0_plus_non_residue_c1 = self.c0.add(cs.ns(|| "a0 + non_residue * a1"), &self.c1)?;
258        let one_plus_non_residue_v0 = v0.mul_by_constant(
259            cs.ns(|| "1 + non_residue * v0"),
260            &(P::Fp::one() + &P::NONRESIDUE),
261        )?;
262
263        self.c0 = a0_plus_a1
264            .mul(
265                cs.ns(|| "(a0 + a1) * (a0 + non_residue * a1)"),
266                &a0_plus_non_residue_c1,
267            )?
268            .sub(cs.ns(|| "- (1 + non_residue) v0"), &one_plus_non_residue_v0)?;
269
270        v0.double_in_place(cs.ns(|| "2v0"))?;
271        self.c1 = v0;
272
273        Ok(self)
274    }
275
276    #[inline]
277    fn inverse<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Self, SynthesisError> {
278        let inverse = Self::alloc(&mut cs.ns(|| "alloc inverse"), || {
279            self.get_value().and_then(|val| val.inverse()).get()
280        })?;
281
282        // Karatsuba multiplication for Fp2 with the inverse:
283        //     v0 = A.c0 * B.c0
284        //     v1 = A.c1 * B.c1
285        //
286        //      1 = v0 + non_residue * v1
287        //  => v0 = 1 - non_residue * v1
288        //
289        //      0 = result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1
290        //  => v0 + v1 = (A.c0 + A.c1) * (B.c0 + B.c1)
291        //  => 1 + (1 - non_residue) * v1 = (A.c0 + A.c1) * (B.c0 + B.c1)
292        // Enforced with 2 constraints:
293        //     A.c1 * B.c1 = v1
294        //  => 1 + (1 - non_residue) * v1 = (A.c0 + A.c1) * (B.c0 + B.c1)
295        // Reference:
296        // "Multiplication and Squaring on Pairing-Friendly Fields"
297        // Devegili, OhEigeartaigh, Scott, Dahab
298
299        // Constraint 1
300        let mut v1 = self.c1.mul(cs.ns(|| "inv_constraint_1"), &inverse.c1)?;
301
302        // Constraint 2
303        let a0_plus_a1 = self.c0.add(cs.ns(|| "a0 + a1"), &self.c1)?;
304        let b0_plus_b1 = inverse.c0.add(cs.ns(|| "b0 + b1"), &inverse.c1)?;
305
306        let one = P::Fp::one();
307        let rhs = v1
308            .mul_by_constant_in_place(cs.ns(|| "(1 - nonresidue) * v1"), &(one - &P::NONRESIDUE))?
309            .add_constant_in_place(cs.ns(|| "add one"), &one)?;
310        a0_plus_a1.mul_equals(cs.ns(|| "inv_constraint_2"), &b0_plus_b1, rhs)?;
311        Ok(inverse)
312    }
313
314    fn mul_equals<CS: ConstraintSystem<ConstraintF>>(
315        &self,
316        mut cs: CS,
317        other: &Self,
318        result: &Self,
319    ) -> Result<(), SynthesisError> {
320        // Karatsuba multiplication for Fp2:
321        //     v0 = A.c0 * B.c0
322        //     v1 = A.c1 * B.c1
323        //     result.c0 = v0 + non_residue * v1
324        //     result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1
325        // Enforced with 3 constraints:
326        //     A.c1 * B.c1 = v1
327        //     A.c0 * B.c0 = result.c0 - non_residue * v1
328        //     (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + result.c0 + (1 - non_residue) * v1
329        // Reference:
330        // "Multiplication and Squaring on Pairing-Friendly Fields"
331        // Devegili, OhEigeartaigh, Scott, Dahab
332        let mul_cs = &mut cs.ns(|| "mul");
333
334        // Compute v1
335        let mut v1 = self.c1.mul(mul_cs.ns(|| "v1"), &other.c1)?;
336
337        // Perform second check
338        let non_residue_times_v1 =
339            v1.mul_by_constant(mul_cs.ns(|| "non_residue * v0"), &P::NONRESIDUE)?;
340        let rhs = result
341            .c0
342            .sub(mul_cs.ns(|| "sub from result.c0"), &non_residue_times_v1)?;
343        self.c0
344            .mul_equals(mul_cs.ns(|| "second check"), &other.c0, &rhs)?;
345
346        // Last check
347        let a0_plus_a1 = self.c0.add(mul_cs.ns(|| "a0 + a1"), &self.c1)?;
348        let b0_plus_b1 = other.c0.add(mul_cs.ns(|| "b0 + b1"), &other.c1)?;
349        let one_minus_non_residue_v1 =
350            v1.sub_in_place(mul_cs.ns(|| "sub from v1"), &non_residue_times_v1)?;
351
352        let result_c1_plus_result_c0_plus_one_minus_non_residue_v1 = result
353            .c1
354            .add(mul_cs.ns(|| "c1 + c0"), &result.c0)?
355            .add(mul_cs.ns(|| "rest of stuff"), one_minus_non_residue_v1)?;
356
357        a0_plus_a1.mul_equals(
358            mul_cs.ns(|| "third check"),
359            &b0_plus_b1,
360            &result_c1_plus_result_c0_plus_one_minus_non_residue_v1,
361        )?;
362
363        Ok(())
364    }
365
366    fn frobenius_map<CS: ConstraintSystem<ConstraintF>>(
367        &self,
368        cs: CS,
369        power: usize,
370    ) -> Result<Self, SynthesisError> {
371        let mut result = self.clone();
372        let _ = result.frobenius_map_in_place(cs, power)?;
373        Ok(result)
374    }
375
376    fn frobenius_map_in_place<CS: ConstraintSystem<ConstraintF>>(
377        &mut self,
378        cs: CS,
379        power: usize,
380    ) -> Result<&mut Self, SynthesisError> {
381        self.c1
382            .mul_by_constant_in_place(cs, &P::FROBENIUS_COEFF_FP2_C1[power % 2])?;
383        Ok(self)
384    }
385
386    #[inline]
387    fn add_constant<CS: ConstraintSystem<ConstraintF>>(
388        &self,
389        cs: CS,
390        other: &Fp2<P>,
391    ) -> Result<Self, SynthesisError> {
392        let mut result = self.clone();
393        let _ = result.add_constant_in_place(cs, other)?;
394        Ok(result)
395    }
396
397    #[inline]
398    fn add_constant_in_place<CS: ConstraintSystem<ConstraintF>>(
399        &mut self,
400        mut cs: CS,
401        other: &Fp2<P>,
402    ) -> Result<&mut Self, SynthesisError> {
403        self.c0.add_constant_in_place(cs.ns(|| "c0"), &other.c0)?;
404        self.c1.add_constant_in_place(cs.ns(|| "c1"), &other.c1)?;
405        Ok(self)
406    }
407
408    fn mul_by_constant<CS: ConstraintSystem<ConstraintF>>(
409        &self,
410        mut cs: CS,
411        fe: &Fp2<P>,
412    ) -> Result<Self, SynthesisError> {
413        // Karatsuba multiplication (see mul above).
414        // Doesn't need any constraints; returns linear combinations of
415        // `self`'s variables.
416        //
417        // (The operations below are guaranteed to return linear combinations)
418        let (a0, a1) = (&self.c0, &self.c1);
419        let (b0, b1) = (fe.c0, fe.c1);
420        let mut v0 = a0.mul_by_constant(&mut cs.ns(|| "v0"), &b0)?;
421        let beta_v1 = a1.mul_by_constant(&mut cs.ns(|| "v1"), &(b1 * &P::NONRESIDUE))?;
422
423        v0.add_in_place(&mut cs.ns(|| "c0"), &beta_v1)?;
424        let c0 = v0;
425
426        let mut a0b1 = a0.mul_by_constant(&mut cs.ns(|| "a0b1"), &b1)?;
427        let a1b0 = a1.mul_by_constant(&mut cs.ns(|| "a1b0"), &b0)?;
428        a0b1.add_in_place(&mut cs.ns(|| "c1"), &a1b0)?;
429        let c1 = a0b1;
430        Ok(Self::new(c0, c1))
431    }
432
433    fn cost_of_mul() -> usize {
434        3
435    }
436
437    fn cost_of_inv() -> usize {
438        2
439    }
440}
441
442impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> PartialEq for Fp2Gadget<P, ConstraintF> {
443    fn eq(&self, other: &Self) -> bool {
444        self.c0 == other.c0 && self.c1 == other.c1
445    }
446}
447
448impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> Eq for Fp2Gadget<P, ConstraintF> {}
449
450impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> EqGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> {}
451
452impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> ConditionalEqGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> {
453    #[inline]
454    fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>(
455        &self,
456        mut cs: CS,
457        other: &Self,
458        condition: &Boolean,
459    ) -> Result<(), SynthesisError> {
460        self.c0
461            .conditional_enforce_equal(&mut cs.ns(|| "c0"), &other.c0, condition)?;
462        self.c1
463            .conditional_enforce_equal(&mut cs.ns(|| "c1"), &other.c1, condition)?;
464        Ok(())
465    }
466
467    fn cost() -> usize {
468        2
469    }
470}
471
472impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> NEqGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> {
473    #[inline]
474    fn enforce_not_equal<CS: ConstraintSystem<ConstraintF>>(
475        &self,
476        mut cs: CS,
477        other: &Self,
478    ) -> Result<(), SynthesisError> {
479        self.c0.enforce_not_equal(&mut cs.ns(|| "c0"), &other.c0)?;
480        self.c1.enforce_not_equal(&mut cs.ns(|| "c1"), &other.c1)?;
481        Ok(())
482    }
483
484    fn cost() -> usize {
485        2
486    }
487}
488
489impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> ToBitsGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> {
490    fn to_bits<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError> {
491        let mut c0 = self.c0.to_bits(&mut cs)?;
492        let mut c1 = self.c1.to_bits(cs)?;
493        c0.append(&mut c1);
494        Ok(c0)
495    }
496
497    fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>(
498        &self,
499        mut cs: CS,
500    ) -> Result<Vec<Boolean>, SynthesisError> {
501        let mut c0 = self.c0.to_bits_strict(&mut cs)?;
502        let mut c1 = self.c1.to_bits_strict(cs)?;
503        c0.append(&mut c1);
504        Ok(c0)
505    }
506}
507
508impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> ToBytesGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> {
509    fn to_bytes<CS: ConstraintSystem<ConstraintF>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> {
510        let mut c0 = self.c0.to_bytes(cs.ns(|| "c0"))?;
511        let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?;
512        c0.append(&mut c1);
513        Ok(c0)
514    }
515
516    fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
517        &self,
518        mut cs: CS,
519    ) -> Result<Vec<UInt8>, SynthesisError> {
520        let mut c0 = self.c0.to_bytes_strict(cs.ns(|| "c0"))?;
521        let mut c1 = self.c1.to_bytes_strict(cs.ns(|| "c1"))?;
522        c0.append(&mut c1);
523        Ok(c0)
524    }
525}
526
527impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> Clone for Fp2Gadget<P, ConstraintF> {
528    fn clone(&self) -> Self {
529        Self {
530            c0:      self.c0.clone(),
531            c1:      self.c1.clone(),
532            _params: PhantomData,
533        }
534    }
535}
536
537impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> CondSelectGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> {
538    #[inline]
539    fn conditionally_select<CS: ConstraintSystem<ConstraintF>>(
540        mut cs: CS,
541        cond: &Boolean,
542        first: &Self,
543        second: &Self,
544    ) -> Result<Self, SynthesisError> {
545        let c0 =
546            FpGadget::<ConstraintF>::conditionally_select(&mut cs.ns(|| "c0"), cond, &first.c0, &second.c0)?;
547        let c1 =
548            FpGadget::<ConstraintF>::conditionally_select(&mut cs.ns(|| "c1"), cond, &first.c1, &second.c1)?;
549
550        Ok(Self::new(c0, c1))
551    }
552
553    fn cost() -> usize {
554        2
555    }
556}
557
558impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> TwoBitLookupGadget<ConstraintF> for Fp2Gadget<P, ConstraintF> {
559    type TableConstant = Fp2<P>;
560    fn two_bit_lookup<CS: ConstraintSystem<ConstraintF>>(
561        mut cs: CS,
562        b: &[Boolean],
563        c: &[Self::TableConstant],
564    ) -> Result<Self, SynthesisError> {
565        let c0s = c.iter().map(|f| f.c0).collect::<Vec<_>>();
566        let c1s = c.iter().map(|f| f.c1).collect::<Vec<_>>();
567        let c0 = FpGadget::two_bit_lookup(cs.ns(|| "Lookup c0"), b, &c0s)?;
568        let c1 = FpGadget::two_bit_lookup(cs.ns(|| "Lookup c1"), b, &c1s)?;
569        Ok(Self::new(c0, c1))
570    }
571
572    fn cost() -> usize {
573        2 * <FpGadget<ConstraintF> as TwoBitLookupGadget<ConstraintF>>::cost()
574    }
575}
576
577impl<P: Fp2Parameters<Fp = ConstraintF>, ConstraintF: PrimeField> AllocGadget<Fp2<P>, ConstraintF> for Fp2Gadget<P, ConstraintF> {
578    #[inline]
579    fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
580        mut cs: CS,
581        value_gen: F,
582    ) -> Result<Self, SynthesisError>
583    where
584        F: FnOnce() -> Result<T, SynthesisError>,
585        T: Borrow<Fp2<P>>,
586    {
587        let (c0, c1) = match value_gen() {
588            Ok(fe) => {
589                let fe = *fe.borrow();
590                (Ok(fe.c0), Ok(fe.c1))
591            },
592            Err(_) => (
593                Err(SynthesisError::AssignmentMissing),
594                Err(SynthesisError::AssignmentMissing),
595            ),
596        };
597
598        let c0 = FpGadget::alloc(&mut cs.ns(|| "c0"), || c0)?;
599        let c1 = FpGadget::alloc(&mut cs.ns(|| "c1"), || c1)?;
600        Ok(Self::new(c0, c1))
601    }
602
603    #[inline]
604    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
605        mut cs: CS,
606        value_gen: F,
607    ) -> Result<Self, SynthesisError>
608    where
609        F: FnOnce() -> Result<T, SynthesisError>,
610        T: Borrow<Fp2<P>>,
611    {
612        let (c0, c1) = match value_gen() {
613            Ok(fe) => {
614                let fe = *fe.borrow();
615                (Ok(fe.c0), Ok(fe.c1))
616            },
617            Err(_) => (
618                Err(SynthesisError::AssignmentMissing),
619                Err(SynthesisError::AssignmentMissing),
620            ),
621        };
622
623        let c0 = FpGadget::alloc_input(&mut cs.ns(|| "c0"), || c0)?;
624        let c1 = FpGadget::alloc_input(&mut cs.ns(|| "c1"), || c1)?;
625        Ok(Self::new(c0, c1))
626    }
627}