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