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