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