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