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