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, Field, One, PrimeField, SquareRootField,
  7};
  8use core::{borrow::Borrow, marker::PhantomData};
  9use r1cs_core::{ConstraintSystem, SynthesisError};
 10
 11use crate::{prelude::*, Assignment, 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    #[inline]
295    fn inverse<CS: ConstraintSystem<ConstraintF>>(
296        &self,
297        mut cs: CS,
298    ) -> Result<Self, SynthesisError> {
299        let inverse = Self::alloc(&mut cs.ns(|| "alloc inverse"), || {
300            self.get_value().and_then(|val| val.inverse()).get()
301        })?;
302
303        // Karatsuba multiplication for Fp6 with the inverse:
304        //     v0 = A.c0 * B.c0
305        //     v1 = A.c1 * B.c1
306        //
307        //      1 = v0 + non_residue * v1
308        //  => v0 = 1 - non_residue * v1
309        //
310        //      0 = result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1
311        //  => v0 + v1 = (A.c0 + A.c1) * (B.c0 + B.c1)
312        //  => 1 + (1 - non_residue) * v1 = (A.c0 + A.c1) * (B.c0 + B.c1)
313        // Enforced with 2 constraints:
314        //     A.c1 * B.c1 = v1
315        //  => 1 + (1 - non_residue) * v1 = (A.c0 + A.c1) * (B.c0 + B.c1)
316        // Reference:
317        // "Multiplication and Squaring on Pairing-Friendly Fields"
318        // Devegili, OhEigeartaigh, Scott, Dahab
319
320        // Constraint 1
321        let v1 = self.c1.mul(cs.ns(|| "inv_constraint_1"), &inverse.c1)?;
322
323        // Constraint 2
324        let a0_plus_a1 = self.c0.add(cs.ns(|| "a0 + a1"), &self.c1)?;
325        let b0_plus_b1 = inverse.c0.add(cs.ns(|| "b0 + b1"), &inverse.c1)?;
326
327        let one = Fp3::<<P as Fp6Parameters>::Fp3Params>::one();
328        let rhs = Self::mul_fp3_gadget_by_nonresidue(cs.ns(|| "nr * v1"), &v1)?
329            .sub(cs.ns(|| "sub v1"), &v1)?
330            .negate(cs.ns(|| "negate it"))?
331            .add_constant(cs.ns(|| "add one"), &one)?;
332        a0_plus_a1.mul_equals(cs.ns(|| "inv_constraint_2"), &b0_plus_b1, &rhs)?;
333        Ok(inverse)
334    }
335
336    fn mul_equals<CS: ConstraintSystem<ConstraintF>>(
337        &self,
338        mut cs: CS,
339        other: &Self,
340        result: &Self,
341    ) -> Result<(), SynthesisError> {
342        // Karatsuba multiplication for Fp6:
343        //     v0 = A.c0 * B.c0
344        //     v1 = A.c1 * B.c1
345        //     result.c0 = v0 + non_residue * v1
346        //     result.c1 = (A.c0 + A.c1) * (B.c0 + B.c1) - v0 - v1
347        // Enforced with 3 constraints:
348        //     A.c1 * B.c1 = v1
349        //     A.c0 * B.c0 = result.c0 - non_residue * v1
350        //     (A.c0+A.c1)*(B.c0+B.c1) = result.c1 + result.c0 + (1 - non_residue) * v1
351        // Reference:
352        // "Multiplication and Squaring on Pairing-Friendly Fields"
353        // Devegili, OhEigeartaigh, Scott, Dahab
354        let mul_cs = &mut cs.ns(|| "mul");
355
356        // Compute v1
357        let mut v1 = self.c1.mul(mul_cs.ns(|| "v1"), &other.c1)?;
358
359        // Perform second check
360        let non_residue_times_v1 =
361            Self::mul_fp3_gadget_by_nonresidue(mul_cs.ns(|| "nr * v1"), &v1)?;
362        let rhs = result
363            .c0
364            .sub(mul_cs.ns(|| "sub from result.c0"), &non_residue_times_v1)?;
365        self.c0
366            .mul_equals(mul_cs.ns(|| "second check"), &other.c0, &rhs)?;
367
368        // Last check
369        let a0_plus_a1 = self.c0.add(mul_cs.ns(|| "a0 + a1"), &self.c1)?;
370        let b0_plus_b1 = other.c0.add(mul_cs.ns(|| "b0 + b1"), &other.c1)?;
371        let one_minus_non_residue_v1 =
372            v1.sub_in_place(mul_cs.ns(|| "sub from v1"), &non_residue_times_v1)?;
373
374        let result_c1_plus_result_c0_plus_one_minus_non_residue_v1 = result
375            .c1
376            .add(mul_cs.ns(|| "c1 + c0"), &result.c0)?
377            .add(mul_cs.ns(|| "rest of stuff"), one_minus_non_residue_v1)?;
378
379        a0_plus_a1.mul_equals(
380            mul_cs.ns(|| "third check"),
381            &b0_plus_b1,
382            &result_c1_plus_result_c0_plus_one_minus_non_residue_v1,
383        )?;
384
385        Ok(())
386    }
387
388    fn frobenius_map<CS: ConstraintSystem<ConstraintF>>(
389        &self,
390        cs: CS,
391        power: usize,
392    ) -> Result<Self, SynthesisError> {
393        let mut result = self.clone();
394        let _ = result.frobenius_map_in_place(cs, power)?;
395        Ok(result)
396    }
397
398    fn frobenius_map_in_place<CS: ConstraintSystem<ConstraintF>>(
399        &mut self,
400        mut cs: CS,
401        power: usize,
402    ) -> Result<&mut Self, SynthesisError> {
403        self.c0
404            .frobenius_map_in_place(cs.ns(|| "frob_map1"), power)?;
405        self.c1
406            .frobenius_map_in_place(cs.ns(|| "frob_map2"), power)?;
407        self.c1
408            .mul_by_fp_constant_in_place(cs.ns(|| "mul"), &P::FROBENIUS_COEFF_FP6_C1[power % 6])?;
409        Ok(self)
410    }
411
412    #[inline]
413    fn add_constant<CS: ConstraintSystem<ConstraintF>>(
414        &self,
415        cs: CS,
416        other: &Fp6<P>,
417    ) -> Result<Self, SynthesisError> {
418        let mut result = self.clone();
419        let _ = result.add_constant_in_place(cs, other)?;
420        Ok(result)
421    }
422
423    #[inline]
424    fn add_constant_in_place<CS: ConstraintSystem<ConstraintF>>(
425        &mut self,
426        mut cs: CS,
427        other: &Fp6<P>,
428    ) -> Result<&mut Self, SynthesisError> {
429        self.c0.add_constant_in_place(cs.ns(|| "c0"), &other.c0)?;
430        self.c1.add_constant_in_place(cs.ns(|| "c1"), &other.c1)?;
431        Ok(self)
432    }
433
434    fn mul_by_constant<CS: ConstraintSystem<ConstraintF>>(
435        &self,
436        mut cs: CS,
437        fe: &Fp6<P>,
438    ) -> Result<Self, SynthesisError> {
439        // Karatsuba multiplication (see mul above).
440        // Doesn't need any constraints; returns linear combinations of
441        // `self`'s variables.
442        //
443        // (The operations below are guaranteed to return linear combinations)
444        let (a0, a1) = (&self.c0, &self.c1);
445        let (b0, b1) = (fe.c0, fe.c1);
446        let mut v0 = a0.mul_by_constant(&mut cs.ns(|| "v0"), &b0)?;
447        let mut v1 = Self::mul_fp3_gadget_by_nonresidue(&mut cs.ns(|| "v1"), a1)?;
448        let beta_v1 = v1.mul_by_constant_in_place(&mut cs.ns(|| "beta * v1"), &b1)?;
449
450        v0.add_in_place(&mut cs.ns(|| "c0"), &beta_v1)?;
451        let c0 = v0;
452
453        let mut a0b1 = a0.mul_by_constant(&mut cs.ns(|| "a0b1"), &b1)?;
454        let a1b0 = a1.mul_by_constant(&mut cs.ns(|| "a1b0"), &b0)?;
455        a0b1.add_in_place(&mut cs.ns(|| "c1"), &a1b0)?;
456        let c1 = a0b1;
457        Ok(Self::new(c0, c1))
458    }
459
460    fn cost_of_mul() -> usize {
461        3 * <Fp3Gadget<P, ConstraintF> as FieldGadget<Fp3<P::Fp3Params>, ConstraintF>>::cost_of_mul(
462        )
463    }
464
465    fn cost_of_mul_equals() -> usize {
466        Self::cost_of_mul()
467    }
468
469    fn cost_of_inv() -> usize {
470        unimplemented!()
471    }
472}
473
474impl<P, ConstraintF: PrimeField + SquareRootField> PartialEq for Fp6Gadget<P, ConstraintF>
475where
476    P: Fp6Parameters,
477    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
478{
479    fn eq(&self, other: &Self) -> bool {
480        self.c0 == other.c0 && self.c1 == other.c1
481    }
482}
483
484impl<P, ConstraintF: PrimeField + SquareRootField> Eq for Fp6Gadget<P, ConstraintF>
485where
486    P: Fp6Parameters,
487    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
488{
489}
490
491impl<P, ConstraintF: PrimeField + SquareRootField> EqGadget<ConstraintF>
492    for Fp6Gadget<P, ConstraintF>
493where
494    P: Fp6Parameters,
495    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
496{
497}
498
499impl<P, ConstraintF: PrimeField + SquareRootField> ConditionalEqGadget<ConstraintF>
500    for Fp6Gadget<P, ConstraintF>
501where
502    P: Fp6Parameters,
503    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
504{
505    #[inline]
506    fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>(
507        &self,
508        mut cs: CS,
509        other: &Self,
510        condition: &Boolean,
511    ) -> Result<(), SynthesisError> {
512        self.c0
513            .conditional_enforce_equal(&mut cs.ns(|| "c0"), &other.c0, condition)?;
514        self.c1
515            .conditional_enforce_equal(&mut cs.ns(|| "c1"), &other.c1, condition)?;
516        Ok(())
517    }
518
519    fn cost() -> usize {
520        2 * <Fp3Gadget<P, ConstraintF> as ConditionalEqGadget<ConstraintF>>::cost()
521    }
522}
523
524impl<P, ConstraintF: PrimeField + SquareRootField> NEqGadget<ConstraintF>
525    for Fp6Gadget<P, ConstraintF>
526where
527    P: Fp6Parameters,
528    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
529{
530    #[inline]
531    fn enforce_not_equal<CS: ConstraintSystem<ConstraintF>>(
532        &self,
533        mut cs: CS,
534        other: &Self,
535    ) -> Result<(), SynthesisError> {
536        self.c0.enforce_not_equal(&mut cs.ns(|| "c0"), &other.c0)?;
537        self.c1.enforce_not_equal(&mut cs.ns(|| "c1"), &other.c1)?;
538        Ok(())
539    }
540
541    fn cost() -> usize {
542        2 * <Fp3Gadget<P, ConstraintF> as NEqGadget<ConstraintF>>::cost()
543    }
544}
545
546impl<P, ConstraintF: PrimeField + SquareRootField> ToBitsGadget<ConstraintF>
547    for Fp6Gadget<P, ConstraintF>
548where
549    P: Fp6Parameters,
550    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
551{
552    fn to_bits<CS: ConstraintSystem<ConstraintF>>(
553        &self,
554        mut cs: CS,
555    ) -> Result<Vec<Boolean>, SynthesisError> {
556        let mut c0 = self.c0.to_bits(cs.ns(|| "c0"))?;
557        let mut c1 = self.c1.to_bits(cs.ns(|| "c1"))?;
558        c0.append(&mut c1);
559        Ok(c0)
560    }
561
562    fn to_non_unique_bits<CS: ConstraintSystem<ConstraintF>>(
563        &self,
564        mut cs: CS,
565    ) -> Result<Vec<Boolean>, SynthesisError> {
566        let mut c0 = self.c0.to_non_unique_bits(cs.ns(|| "c0"))?;
567        let mut c1 = self.c1.to_non_unique_bits(cs.ns(|| "c1"))?;
568        c0.append(&mut c1);
569        Ok(c0)
570    }
571}
572
573impl<P, ConstraintF: PrimeField + SquareRootField> ToBytesGadget<ConstraintF>
574    for Fp6Gadget<P, ConstraintF>
575where
576    P: Fp6Parameters,
577    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
578{
579    fn to_bytes<CS: ConstraintSystem<ConstraintF>>(
580        &self,
581        mut cs: CS,
582    ) -> Result<Vec<UInt8>, SynthesisError> {
583        let mut c0 = self.c0.to_bytes(cs.ns(|| "c0"))?;
584        let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?;
585        c0.append(&mut c1);
586        Ok(c0)
587    }
588
589    fn to_non_unique_bytes<CS: ConstraintSystem<ConstraintF>>(
590        &self,
591        mut cs: CS,
592    ) -> Result<Vec<UInt8>, SynthesisError> {
593        let mut c0 = self.c0.to_non_unique_bytes(cs.ns(|| "c0"))?;
594        let mut c1 = self.c1.to_non_unique_bytes(cs.ns(|| "c1"))?;
595        c0.append(&mut c1);
596        Ok(c0)
597    }
598}
599
600impl<P, ConstraintF: PrimeField + SquareRootField> Clone for Fp6Gadget<P, ConstraintF>
601where
602    P: Fp6Parameters,
603    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
604{
605    fn clone(&self) -> Self {
606        Self {
607            c0:      self.c0.clone(),
608            c1:      self.c1.clone(),
609            _params: PhantomData,
610        }
611    }
612}
613
614impl<P, ConstraintF: PrimeField + SquareRootField> CondSelectGadget<ConstraintF>
615    for Fp6Gadget<P, ConstraintF>
616where
617    P: Fp6Parameters,
618    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
619{
620    #[inline]
621    fn conditionally_select<CS: ConstraintSystem<ConstraintF>>(
622        mut cs: CS,
623        cond: &Boolean,
624        first: &Self,
625        second: &Self,
626    ) -> Result<Self, SynthesisError> {
627        let c0 = Fp3Gadget::<P, ConstraintF>::conditionally_select(
628            &mut cs.ns(|| "c0"),
629            cond,
630            &first.c0,
631            &second.c0,
632        )?;
633        let c1 = Fp3Gadget::<P, ConstraintF>::conditionally_select(
634            &mut cs.ns(|| "c1"),
635            cond,
636            &first.c1,
637            &second.c1,
638        )?;
639
640        Ok(Self::new(c0, c1))
641    }
642
643    fn cost() -> usize {
644        2 * <Fp3Gadget<P, ConstraintF> as CondSelectGadget<ConstraintF>>::cost()
645    }
646}
647
648impl<P, ConstraintF: PrimeField + SquareRootField> TwoBitLookupGadget<ConstraintF>
649    for Fp6Gadget<P, ConstraintF>
650where
651    P: Fp6Parameters,
652    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
653{
654    type TableConstant = Fp6<P>;
655    fn two_bit_lookup<CS: ConstraintSystem<ConstraintF>>(
656        mut cs: CS,
657        b: &[Boolean],
658        c: &[Self::TableConstant],
659    ) -> Result<Self, SynthesisError> {
660        let c0s = c.iter().map(|f| f.c0).collect::<Vec<_>>();
661        let c1s = c.iter().map(|f| f.c1).collect::<Vec<_>>();
662        let c0 = Fp3Gadget::<P, ConstraintF>::two_bit_lookup(cs.ns(|| "Lookup c0"), b, &c0s)?;
663        let c1 = Fp3Gadget::<P, ConstraintF>::two_bit_lookup(cs.ns(|| "Lookup c1"), b, &c1s)?;
664        Ok(Self::new(c0, c1))
665    }
666
667    fn cost() -> usize {
668        2 * <Fp3Gadget<P, ConstraintF> as TwoBitLookupGadget<ConstraintF>>::cost()
669    }
670}
671
672impl<P, ConstraintF: PrimeField + SquareRootField> ThreeBitCondNegLookupGadget<ConstraintF>
673    for Fp6Gadget<P, ConstraintF>
674where
675    P: Fp6Parameters,
676    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
677{
678    type TableConstant = Fp6<P>;
679
680    fn three_bit_cond_neg_lookup<CS: ConstraintSystem<ConstraintF>>(
681        mut cs: CS,
682        b: &[Boolean],
683        b0b1: &Boolean,
684        c: &[Self::TableConstant],
685    ) -> Result<Self, SynthesisError> {
686        let c0s = c.iter().map(|f| f.c0).collect::<Vec<_>>();
687        let c1s = c.iter().map(|f| f.c1).collect::<Vec<_>>();
688        let c0 = Fp3Gadget::<P, ConstraintF>::three_bit_cond_neg_lookup(
689            cs.ns(|| "Lookup c0"),
690            b,
691            b0b1,
692            &c0s,
693        )?;
694        let c1 = Fp3Gadget::<P, ConstraintF>::three_bit_cond_neg_lookup(
695            cs.ns(|| "Lookup c1"),
696            b,
697            b0b1,
698            &c1s,
699        )?;
700        Ok(Self::new(c0, c1))
701    }
702
703    fn cost() -> usize {
704        2 * <Fp3Gadget<P, ConstraintF> as ThreeBitCondNegLookupGadget<ConstraintF>>::cost()
705    }
706}
707
708impl<P, ConstraintF: PrimeField + SquareRootField> AllocGadget<Fp6<P>, ConstraintF>
709    for Fp6Gadget<P, ConstraintF>
710where
711    P: Fp6Parameters,
712    P::Fp3Params: Fp3Parameters<Fp = ConstraintF>,
713{
714    #[inline]
715    fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
716        mut cs: CS,
717        value_gen: F,
718    ) -> Result<Self, SynthesisError>
719    where
720        F: FnOnce() -> Result<T, SynthesisError>,
721        T: Borrow<Fp6<P>>,
722    {
723        let (c0, c1) = match value_gen() {
724            Ok(fe) => {
725                let fe = *fe.borrow();
726                (Ok(fe.c0), Ok(fe.c1))
727            },
728            Err(_) => (
729                Err(SynthesisError::AssignmentMissing),
730                Err(SynthesisError::AssignmentMissing),
731            ),
732        };
733
734        let c0 = Fp3Gadget::<P, ConstraintF>::alloc(&mut cs.ns(|| "c0"), || c0)?;
735        let c1 = Fp3Gadget::<P, ConstraintF>::alloc(&mut cs.ns(|| "c1"), || c1)?;
736        Ok(Self::new(c0, c1))
737    }
738
739    #[inline]
740    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
741        mut cs: CS,
742        value_gen: F,
743    ) -> Result<Self, SynthesisError>
744    where
745        F: FnOnce() -> Result<T, SynthesisError>,
746        T: Borrow<Fp6<P>>,
747    {
748        let (c0, c1) = match value_gen() {
749            Ok(fe) => {
750                let fe = *fe.borrow();
751                (Ok(fe.c0), Ok(fe.c1))
752            },
753            Err(_) => (
754                Err(SynthesisError::AssignmentMissing),
755                Err(SynthesisError::AssignmentMissing),
756            ),
757        };
758
759        let c0 = Fp3Gadget::<P, ConstraintF>::alloc_input(&mut cs.ns(|| "c0"), || c0)?;
760        let c1 = Fp3Gadget::<P, ConstraintF>::alloc_input(&mut cs.ns(|| "c1"), || c1)?;
761        Ok(Self::new(c0, c1))
762    }
763}