arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/r1cs-std/src/fields/fp6_3over2.rs
r1cs-std/src/fields/fp6_3over2.rsRaw
   1use algebra::{
   2    fields::{
   3        fp6_3over2::{Fp6, Fp6Parameters},
   4        Field, Fp2Parameters,
   5    },
   6    PrimeField,
   7};
   8use core::{borrow::Borrow, marker::PhantomData};
   9use r1cs_core::{ConstraintSystem, ConstraintVar, SynthesisError};
  10
  11use crate::{prelude::*, Vec};
  12
  13type Fp2Gadget<P, ConstraintF> =
  14    super::fp2::Fp2Gadget<<P as Fp6Parameters>::Fp2Params, ConstraintF>;
  15
  16#[derive(Derivative)]
  17#[derivative(Debug(bound = "ConstraintF: PrimeField"))]
  18#[must_use]
  19pub struct Fp6Gadget<P, ConstraintF: PrimeField>
  20where
  21    P: Fp6Parameters,
  22    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
  23{
  24    pub c0: Fp2Gadget<P, ConstraintF>,
  25    pub c1: Fp2Gadget<P, ConstraintF>,
  26    pub c2: Fp2Gadget<P, ConstraintF>,
  27    #[derivative(Debug = "ignore")]
  28    _params: PhantomData<P>,
  29}
  30
  31impl<P, ConstraintF: PrimeField> ToConstraintFieldGadget<ConstraintF> for Fp6Gadget<P, ConstraintF>
  32where
  33    P: Fp6Parameters,
  34    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
  35{
  36    fn to_constraint_field<CS: ConstraintSystem<ConstraintF>>(
  37        &self,
  38        mut cs: CS,
  39    ) -> Result<Vec<FpGadget<ConstraintF>>, SynthesisError> {
  40        let mut res = Vec::new();
  41
  42        let mut c0_gadget = self.c0.to_constraint_field(&mut cs.ns(|| "c0"))?;
  43        let mut c1_gadget = self.c1.to_constraint_field(&mut cs.ns(|| "c1"))?;
  44        let mut c2_gadget = self.c2.to_constraint_field(&mut cs.ns(|| "c2"))?;
  45
  46        res.append(&mut c0_gadget);
  47        res.append(&mut c1_gadget);
  48        res.append(&mut c2_gadget);
  49
  50        Ok(res)
  51    }
  52}
  53
  54impl<P, ConstraintF: PrimeField> Fp6Gadget<P, ConstraintF>
  55where
  56    P: Fp6Parameters,
  57    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
  58{
  59    #[inline]
  60    pub fn new(
  61        c0: Fp2Gadget<P, ConstraintF>,
  62        c1: Fp2Gadget<P, ConstraintF>,
  63        c2: Fp2Gadget<P, ConstraintF>,
  64    ) -> Self {
  65        Self {
  66            c0,
  67            c1,
  68            c2,
  69            _params: PhantomData,
  70        }
  71    }
  72    /// Multiply a Fp2Gadget by cubic nonresidue P::NONRESIDUE.
  73    #[inline]
  74    pub fn mul_fp2_gadget_by_nonresidue<CS: ConstraintSystem<ConstraintF>>(
  75        cs: CS,
  76        fe: &Fp2Gadget<P, ConstraintF>,
  77    ) -> Result<Fp2Gadget<P, ConstraintF>, SynthesisError> {
  78        fe.mul_by_constant(cs, &P::NONRESIDUE)
  79    }
  80
  81    #[inline]
  82    pub fn mul_by_0_c1_0<CS: ConstraintSystem<ConstraintF>>(
  83        &self,
  84        mut cs: CS,
  85        c1: &Fp2Gadget<P, ConstraintF>,
  86    ) -> Result<Self, SynthesisError> {
  87        // Karatsuba multiplication
  88        // v0 = a0 * b0 = 0
  89
  90        // v1 = a1 * b1
  91        let v1 = self.c1.mul(cs.ns(|| "first mul"), c1)?;
  92
  93        // v2 = a2 * b2 = 0
  94
  95        let a1_plus_a2 = self.c1.add(cs.ns(|| "a1 + a2"), &self.c2)?;
  96        let b1_plus_b2 = c1.clone();
  97
  98        let a0_plus_a1 = self.c0.add(cs.ns(|| "a0 + a1"), &self.c1)?;
  99
 100        // c0 = (NONRESIDUE * ((a1 + a2)*(b1 + b2) - v1 - v2)) + v0
 101        //    = NONRESIDUE * ((a1 + a2) * b1 - v1)
 102        let c0 = a1_plus_a2
 103            .mul(cs.ns(|| "second mul"), &b1_plus_b2)?
 104            .sub(cs.ns(|| "first sub"), &v1)?
 105            .mul_by_constant(cs.ns(|| "mul_by_nonresidue"), &P::NONRESIDUE)?;
 106
 107        // c1 = (a0 + a1) * (b0 + b1) - v0 - v1 + NONRESIDUE * v2
 108        //    = (a0 + a1) * b1 - v1
 109        let c1 = a0_plus_a1
 110            .mul(cs.ns(|| "third mul"), &c1)?
 111            .sub(cs.ns(|| "second sub"), &v1)?;
 112        // c2 = (a0 + a2) * (b0 + b2) - v0 - v2 + v1
 113        //    = v1
 114        let c2 = v1;
 115        Ok(Self::new(c0, c1, c2))
 116    }
 117
 118    // #[inline]
 119    pub fn mul_by_c0_c1_0<CS: ConstraintSystem<ConstraintF>>(
 120        &self,
 121        mut cs: CS,
 122        c0: &Fp2Gadget<P, ConstraintF>,
 123        c1: &Fp2Gadget<P, ConstraintF>,
 124    ) -> Result<Self, SynthesisError> {
 125        let v0 = self.c0.mul(cs.ns(|| "v0"), c0)?;
 126        let v1 = self.c1.mul(cs.ns(|| "v1"), c1)?;
 127        // v2 = 0.
 128
 129        let a1_plus_a2 = self.c1.add(cs.ns(|| "a1 + a2"), &self.c2)?;
 130        let a0_plus_a1 = self.c0.add(cs.ns(|| "a0 + a1"), &self.c1)?;
 131        let a0_plus_a2 = self.c0.add(cs.ns(|| "a0 + a2"), &self.c2)?;
 132
 133        let b1_plus_b2 = c1.clone();
 134        let b0_plus_b1 = c0.add(cs.ns(|| "b0 + b1"), &c1)?;
 135        let b0_plus_b2 = c0.clone();
 136
 137        let c0 = {
 138            let cs = &mut cs.ns(|| "c0");
 139            a1_plus_a2
 140                .mul(cs.ns(|| "(a1 + a2) * (b1 + b2)"), &b1_plus_b2)?
 141                .sub(cs.ns(|| "sub v1"), &v1)?
 142                .mul_by_constant(cs.ns(|| "First mul_by_nonresidue"), &P::NONRESIDUE)?
 143                .add(cs.ns(|| "add v0"), &v0)?
 144        };
 145
 146        let c1 = {
 147            let cs = &mut cs.ns(|| "c1");
 148            a0_plus_a1
 149                .mul(cs.ns(|| "(a0 + a1) * (b0 + b1)"), &b0_plus_b1)?
 150                .sub(cs.ns(|| "sub v0"), &v0)?
 151                .sub(cs.ns(|| "sub v1"), &v1)?
 152        };
 153
 154        let c2 = {
 155            a0_plus_a2
 156                .mul(cs.ns(|| "(a0 + a2) * (b0 + b2)"), &b0_plus_b2)?
 157                .sub(cs.ns(|| "sub v0"), &v0)?
 158                .add(cs.ns(|| "add v1"), &v1)?
 159        };
 160
 161        Ok(Self::new(c0, c1, c2))
 162    }
 163}
 164
 165impl<P, ConstraintF: PrimeField> FieldGadget<Fp6<P>, ConstraintF> for Fp6Gadget<P, ConstraintF>
 166where
 167    P: Fp6Parameters,
 168    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 169{
 170    type Variable = (
 171        (ConstraintVar<ConstraintF>, ConstraintVar<ConstraintF>),
 172        (ConstraintVar<ConstraintF>, ConstraintVar<ConstraintF>),
 173        (ConstraintVar<ConstraintF>, ConstraintVar<ConstraintF>),
 174    );
 175
 176    #[inline]
 177    fn get_value(&self) -> Option<Fp6<P>> {
 178        match (
 179            self.c0.get_value(),
 180            self.c1.get_value(),
 181            self.c2.get_value(),
 182        ) {
 183            (Some(c0), Some(c1), Some(c2)) => Some(Fp6::new(c0, c1, c2)),
 184            (..) => None,
 185        }
 186    }
 187
 188    #[inline]
 189    fn get_variable(&self) -> Self::Variable {
 190        (
 191            self.c0.get_variable(),
 192            self.c1.get_variable(),
 193            self.c2.get_variable(),
 194        )
 195    }
 196
 197    #[inline]
 198    fn zero<CS: ConstraintSystem<ConstraintF>>(mut cs: CS) -> Result<Self, SynthesisError> {
 199        let c0 = Fp2Gadget::<P, ConstraintF>::zero(cs.ns(|| "c0"))?;
 200        let c1 = Fp2Gadget::<P, ConstraintF>::zero(cs.ns(|| "c1"))?;
 201        let c2 = Fp2Gadget::<P, ConstraintF>::zero(cs.ns(|| "c2"))?;
 202        Ok(Self::new(c0, c1, c2))
 203    }
 204
 205    #[inline]
 206    fn one<CS: ConstraintSystem<ConstraintF>>(mut cs: CS) -> Result<Self, SynthesisError> {
 207        let c0 = Fp2Gadget::<P, ConstraintF>::one(cs.ns(|| "c0"))?;
 208        let c1 = Fp2Gadget::<P, ConstraintF>::zero(cs.ns(|| "c1"))?;
 209        let c2 = Fp2Gadget::<P, ConstraintF>::zero(cs.ns(|| "c2"))?;
 210        Ok(Self::new(c0, c1, c2))
 211    }
 212
 213    #[inline]
 214    fn conditionally_add_constant<CS: ConstraintSystem<ConstraintF>>(
 215        &self,
 216        mut cs: CS,
 217        bit: &Boolean,
 218        coeff: Fp6<P>,
 219    ) -> Result<Self, SynthesisError> {
 220        let c0 = self
 221            .c0
 222            .conditionally_add_constant(cs.ns(|| "c0"), bit, coeff.c0)?;
 223        let c1 = self
 224            .c1
 225            .conditionally_add_constant(cs.ns(|| "c1"), bit, coeff.c1)?;
 226        let c2 = self
 227            .c2
 228            .conditionally_add_constant(cs.ns(|| "c2"), bit, coeff.c2)?;
 229        Ok(Self::new(c0, c1, c2))
 230    }
 231
 232    #[inline]
 233    fn add<CS: ConstraintSystem<ConstraintF>>(
 234        &self,
 235        mut cs: CS,
 236        other: &Self,
 237    ) -> Result<Self, SynthesisError> {
 238        let c0 = self.c0.add(&mut cs.ns(|| "add c0"), &other.c0)?;
 239        let c1 = self.c1.add(&mut cs.ns(|| "add c1"), &other.c1)?;
 240        let c2 = self.c2.add(&mut cs.ns(|| "add c2"), &other.c2)?;
 241        Ok(Self::new(c0, c1, c2))
 242    }
 243
 244    #[inline]
 245    fn sub<CS: ConstraintSystem<ConstraintF>>(
 246        &self,
 247        mut cs: CS,
 248        other: &Self,
 249    ) -> Result<Self, SynthesisError> {
 250        let c0 = self.c0.sub(&mut cs.ns(|| "sub c0"), &other.c0)?;
 251        let c1 = self.c1.sub(&mut cs.ns(|| "sub c1"), &other.c1)?;
 252        let c2 = self.c2.sub(&mut cs.ns(|| "sub c2"), &other.c2)?;
 253        Ok(Self::new(c0, c1, c2))
 254    }
 255
 256    #[inline]
 257    fn negate<CS: ConstraintSystem<ConstraintF>>(
 258        &self,
 259        mut cs: CS,
 260    ) -> Result<Self, SynthesisError> {
 261        let c0 = self.c0.negate(&mut cs.ns(|| "negate c0"))?;
 262        let c1 = self.c1.negate(&mut cs.ns(|| "negate c1"))?;
 263        let c2 = self.c2.negate(&mut cs.ns(|| "negate c2"))?;
 264        Ok(Self::new(c0, c1, c2))
 265    }
 266
 267    #[inline]
 268    fn negate_in_place<CS: ConstraintSystem<ConstraintF>>(
 269        &mut self,
 270        mut cs: CS,
 271    ) -> Result<&mut Self, SynthesisError> {
 272        self.c0.negate_in_place(&mut cs.ns(|| "negate c0"))?;
 273        self.c1.negate_in_place(&mut cs.ns(|| "negate c1"))?;
 274        self.c2.negate_in_place(&mut cs.ns(|| "negate c2"))?;
 275        Ok(self)
 276    }
 277
 278    /// Use the Toom-Cook-3x method to compute multiplication.
 279    #[inline]
 280    fn mul<CS: ConstraintSystem<ConstraintF>>(
 281        &self,
 282        mut cs: CS,
 283        other: &Self,
 284    ) -> Result<Self, SynthesisError> {
 285        // Uses Toom-Cook-3x multiplication from
 286        //
 287        // Reference:
 288        // "Multiplication and Squaring on Pairing-Friendly Fields"
 289        //    Devegili, OhEigeartaigh, Scott, Dahab
 290
 291        // v0 = a(0)b(0)   = a0 * b0
 292        let v0 = self.c0.mul(&mut cs.ns(|| "Calc v0"), &other.c0)?;
 293
 294        // v1 = a(1)b(1)   = (a0 + a1 + a2)(b0 + b1 + b2)
 295        let v1 = {
 296            let mut v1_cs = cs.ns(|| "compute v1");
 297            let a0_plus_a1_plus_a2 = self
 298                .c0
 299                .add(v1_cs.ns(|| "a0 + a1"), &self.c1)?
 300                .add(v1_cs.ns(|| "a0 + a1 + a2"), &self.c2)?;
 301            let b0_plus_b1_plus_b2 = other
 302                .c0
 303                .add(v1_cs.ns(|| "b0 + b1"), &other.c1)?
 304                .add(v1_cs.ns(|| "b0 + b1 + b2"), &other.c2)?;
 305
 306            a0_plus_a1_plus_a2.mul(
 307                v1_cs.ns(|| "(a0 + a1 + a2)(b0 + b1 + b2)"),
 308                &b0_plus_b1_plus_b2,
 309            )?
 310        };
 311
 312        // v2 = a(−1)b(−1) = (a0 − a1 + a2)(b0 − b1 + b2)
 313        let v2 = {
 314            let mut v2_cs = cs.ns(|| "compute v2");
 315
 316            let a0_minus_a1_plus_a2 = self
 317                .c0
 318                .sub(v2_cs.ns(|| "a0 - a1"), &self.c1)?
 319                .add(v2_cs.ns(|| "a0 - a1 + a2"), &self.c2)?;
 320
 321            let b0_minus_b1_plus_b2 = other
 322                .c0
 323                .sub(v2_cs.ns(|| "b0 - b1"), &other.c1)?
 324                .add(v2_cs.ns(|| "b0 - b1 + b2"), &other.c2)?;
 325
 326            a0_minus_a1_plus_a2.mul(
 327                v2_cs.ns(|| "(a0 - a1 + a2)(b0 - b1 + b2)"),
 328                &b0_minus_b1_plus_b2,
 329            )?
 330        };
 331
 332        // v3 = a(2)b(2)   = (a0 + 2a1 + 4a2)(b0 + 2b1 + 4b2)
 333        let v3 = {
 334            let v3_cs = &mut cs.ns(|| "compute v3");
 335
 336            let a1_double = self.c1.double(v3_cs.ns(|| "2 * a1"))?;
 337            let a2_quad = self
 338                .c2
 339                .double(v3_cs.ns(|| "2 * a2"))?
 340                .double(v3_cs.ns(|| "4 * a2"))?;
 341
 342            let a0_plus_2_a1_plus_4_a2 = self
 343                .c0
 344                .add(v3_cs.ns(|| "a0 + 2a1"), &a1_double)?
 345                .add(v3_cs.ns(|| "a0 + 2a1 + 4a2"), &a2_quad)?;
 346
 347            let b1_double = other.c1.double(v3_cs.ns(|| "2 * b1"))?;
 348            let b2_quad = other
 349                .c2
 350                .double(v3_cs.ns(|| "2 * b2"))?
 351                .double(v3_cs.ns(|| "4 * b2"))?;
 352            let b0_plus_2_b1_plus_4_b2 = other
 353                .c0
 354                .add(v3_cs.ns(|| "b0 + 2b1"), &b1_double)?
 355                .add(v3_cs.ns(|| "b0 + 2b1 + 4b2"), &b2_quad)?;
 356
 357            a0_plus_2_a1_plus_4_a2.mul(
 358                v3_cs.ns(|| "(a0 + 2a1 + 4a2)(b0 + 2b1 + 4b2)"),
 359                &b0_plus_2_b1_plus_4_b2,
 360            )?
 361        };
 362
 363        // v4 = a(∞)b(∞)   = a2 * b2
 364        let v4 = self.c2.mul(cs.ns(|| "v2: a2 * b2"), &other.c2)?;
 365
 366        let two = <P::Fp2Params as Fp2Parameters>::Fp::one().double();
 367        let six = two.double() + &two;
 368        let mut two_and_six = [two, six];
 369        algebra::fields::batch_inversion(&mut two_and_six);
 370        let (two_inverse, six_inverse) = (two_and_six[0], two_and_six[1]);
 371
 372        let half_v0 = v0.mul_by_fp_constant(cs.ns(|| "half_v0"), &two_inverse)?;
 373        let half_v1 = v1.mul_by_fp_constant(cs.ns(|| "half_v1"), &two_inverse)?;
 374        let one_sixth_v2 = v2.mul_by_fp_constant(cs.ns(|| "v2_by_six"), &six_inverse)?;
 375        let one_sixth_v3 = v3.mul_by_fp_constant(cs.ns(|| "v3_by_six"), &six_inverse)?;
 376        let two_v4 = v4.double(cs.ns(|| "2 * v4"))?;
 377
 378        // c0 = v0 + β((1/2)v0 − (1/2)v1 − (1/6)v2 + (1/6)v3 − 2v4)
 379        let c0 = {
 380            let c0_cs = &mut cs.ns(|| "c0");
 381
 382            // No constraints, only get a linear combination back.
 383            let temp = half_v0
 384                .sub(c0_cs.ns(|| "sub1"), &half_v1)?
 385                .sub(c0_cs.ns(|| "sub2"), &one_sixth_v2)?
 386                .add(c0_cs.ns(|| "add3"), &one_sixth_v3)?
 387                .sub(c0_cs.ns(|| "sub4"), &two_v4)?;
 388            let non_residue_times_inner =
 389                temp.mul_by_constant(&mut c0_cs.ns(|| "mul5"), &P::NONRESIDUE)?;
 390            v0.add(c0_cs.ns(|| "add6"), &non_residue_times_inner)?
 391        };
 392
 393        // −(1/2)v0 + v1 − (1/3)v2 − (1/6)v3 + 2v4 + βv4
 394        let c1 = {
 395            let c1_cs = &mut cs.ns(|| "c1");
 396            let one_third_v2 = one_sixth_v2.double(&mut c1_cs.ns(|| "v2_by_3"))?;
 397            let non_residue_v4 =
 398                v4.mul_by_constant(&mut c1_cs.ns(|| "mul_by_beta"), &P::NONRESIDUE)?;
 399
 400            let result = half_v0
 401                .negate(c1_cs.ns(|| "neg1"))?
 402                .add(c1_cs.ns(|| "add2"), &v1)?
 403                .sub(c1_cs.ns(|| "sub3"), &one_third_v2)?
 404                .sub(c1_cs.ns(|| "sub4"), &one_sixth_v3)?
 405                .add(c1_cs.ns(|| "sub5"), &two_v4)?
 406                .add(c1_cs.ns(|| "sub6"), &non_residue_v4)?;
 407            result
 408        };
 409
 410        // -v0 + (1/2)v1 + (1/2)v2 −v4
 411        let c2 = {
 412            let c2_cs = &mut cs.ns(|| "c2");
 413            let half_v2 = v2.mul_by_fp_constant(&mut c2_cs.ns(|| "mul1"), &two_inverse)?;
 414            let result = half_v1
 415                .add(c2_cs.ns(|| "add1"), &half_v2)?
 416                .sub(c2_cs.ns(|| "sub1"), &v4)?
 417                .sub(c2_cs.ns(|| "sub2"), &v0)?;
 418            result
 419        };
 420
 421        Ok(Self::new(c0, c1, c2))
 422    }
 423
 424    /// Use the Chung-Hasan asymmetric squaring formula.
 425    ///
 426    /// (Devegili OhEig Scott Dahab --- Multiplication and Squaring on
 427    /// Abstract Pairing-Friendly
 428    /// Fields.pdf; Section 4 (CH-SQR2))
 429    #[inline]
 430    fn square<CS: ConstraintSystem<ConstraintF>>(
 431        &self,
 432        mut cs: CS,
 433    ) -> Result<Self, SynthesisError> {
 434        let a = self.c0.clone();
 435        let b = self.c1.clone();
 436        let c = self.c2.clone();
 437
 438        let s0 = a.square(cs.ns(|| "s0"))?;
 439        let ab = a.mul(cs.ns(|| "ab"), &b)?;
 440        let s1 = ab.double(cs.ns(|| "s1"))?;
 441        let s2 = a
 442            .sub(cs.ns(|| "a-b"), &b)?
 443            .add(cs.ns(|| "plus c"), &c)?
 444            .square(cs.ns(|| "s2"))?;
 445        let s3 = b.mul(cs.ns(|| "bc"), &c)?.double(cs.ns(|| "s3"))?;
 446        let s4 = c.square(cs.ns(|| "s4"))?;
 447
 448        let c0 = Self::mul_fp2_gadget_by_nonresidue(cs.ns(|| "c0 part 1"), &s3)?
 449            .add(cs.ns(|| "c0"), &s0)?;
 450
 451        let c1 = Self::mul_fp2_gadget_by_nonresidue(cs.ns(|| "c1 part 1"), &s4)?
 452            .add(cs.ns(|| "c1"), &s1)?;
 453
 454        let c2 = s1
 455            .add(cs.ns(|| "c2 part1"), &s2)?
 456            .add(cs.ns(|| "c2 part2"), &s3)?
 457            .sub(cs.ns(|| "c2 part3"), &s0)?
 458            .sub(cs.ns(|| "c2 part4"), &s4)?;
 459
 460        Ok(Self::new(c0, c1, c2))
 461    }
 462
 463    #[inline]
 464    fn mul_equals<CS: ConstraintSystem<ConstraintF>>(
 465        &self,
 466        mut cs: CS,
 467        other: &Self,
 468        result: &Self,
 469    ) -> Result<(), SynthesisError> {
 470        // Karatsuba multiplication for Fp3:
 471        //     v0 = A.c0 * B.c0
 472        //     v1 = A.c1 * B.c1
 473        //     v2 = A.c2 * B.c2
 474        //     result.c0 = v0 + β((a1 + a2)(b1 + b2) − v1 − v2)
 475        //     result.c1 = (a0 + a1)(b0 + b1) − v0 − v1 + βv2
 476        //     result.c2 = (a0 + a2)(b0 + b2) − v0 + v1 − v2,
 477        // We enforce this with six constraints:
 478        //
 479        //     v0 = A.c0 * B.c0
 480        //     v1 = A.c1 * B.c1
 481        //     v2 = A.c2 * B.c2
 482        //
 483        //     result.c0 - v0 + \beta*(v1 + v2) = β(a1 + a2)(b1 + b2))
 484        //     result.c1 + v0 + v1 - βv2        = (a0 + a1)(b0 + b1)
 485        //     result.c2 + v0 - v1 + v2         = (a0 + a2)(b0 + b2)
 486        // Reference:
 487        // "Multiplication and Squaring on Pairing-Friendly Fields"
 488        // Devegili, OhEigeartaigh, Scott, Dahab
 489        //
 490        // This implementation adapted from
 491        // https://github.com/ZencashOfficial/ginger-lib/blob/development/r1cs/gadgets/std/src/fields/fp3.rs
 492        let v0 = self.c0.mul(cs.ns(|| "v0 = a0 * b0"), &other.c0)?;
 493        let v1 = self.c1.mul(cs.ns(|| "v1 = a1 * b1"), &other.c1)?;
 494        let v2 = self.c2.mul(cs.ns(|| "v2 = a2 * b2"), &other.c2)?;
 495
 496        // Check c0
 497        let nr_a1_plus_a2 = self
 498            .c1
 499            .add(cs.ns(|| "a1 + a2"), &self.c2)?
 500            .mul_by_constant(cs.ns(|| "nr*(a1 + a2)"), &P::NONRESIDUE)?;
 501        let b1_plus_b2 = other.c1.add(cs.ns(|| "b1 + b2"), &other.c2)?;
 502        let nr_v1 = v1.mul_by_constant(cs.ns(|| "nr * v1"), &P::NONRESIDUE)?;
 503        let nr_v2 = v2.mul_by_constant(cs.ns(|| "nr * v2"), &P::NONRESIDUE)?;
 504        let to_check = result
 505            .c0
 506            .sub(cs.ns(|| "c0 - v0"), &v0)?
 507            .add(cs.ns(|| "c0 - v0 + nr * v1"), &nr_v1)?
 508            .add(cs.ns(|| "c0 - v0 + nr * v1 + nr * v2"), &nr_v2)?;
 509        nr_a1_plus_a2.mul_equals(cs.ns(|| "check c0"), &b1_plus_b2, &to_check)?;
 510
 511        // Check c1
 512        let a0_plus_a1 = self.c0.add(cs.ns(|| "a0 + a1"), &self.c1)?;
 513        let b0_plus_b1 = other.c0.add(cs.ns(|| "b0 + b1"), &other.c1)?;
 514        let to_check = result
 515            .c1
 516            .sub(cs.ns(|| "c1 - nr * v2"), &nr_v2)?
 517            .add(cs.ns(|| "c1 - nr * v2 + v0"), &v0)?
 518            .add(cs.ns(|| "c1 - nr * v2 + v0 + v1"), &v1)?;
 519        a0_plus_a1.mul_equals(cs.ns(|| "check c1"), &b0_plus_b1, &to_check)?;
 520
 521        // Check c2
 522        let a0_plus_a2 = self.c0.add(cs.ns(|| "a0 + a2"), &self.c2)?;
 523        let b0_plus_b2 = other.c0.add(cs.ns(|| "b0 + b2"), &other.c2)?;
 524        let to_check = result
 525            .c2
 526            .add(cs.ns(|| "c2 + v0"), &v0)?
 527            .sub(cs.ns(|| "c2 + v0 - v1"), &v1)?
 528            .add(cs.ns(|| "c2 + v0 - v1 + v2"), &v2)?;
 529        a0_plus_a2.mul_equals(cs.ns(|| "check c2"), &b0_plus_b2, &to_check)?;
 530        Ok(())
 531    }
 532
 533    #[inline]
 534    fn add_constant<CS: ConstraintSystem<ConstraintF>>(
 535        &self,
 536        mut cs: CS,
 537        other: &Fp6<P>,
 538    ) -> Result<Self, SynthesisError> {
 539        let c0 = self.c0.add_constant(cs.ns(|| "c0"), &other.c0)?;
 540        let c1 = self.c1.add_constant(cs.ns(|| "c1"), &other.c1)?;
 541        let c2 = self.c2.add_constant(cs.ns(|| "c2"), &other.c2)?;
 542
 543        Ok(Self::new(c0, c1, c2))
 544    }
 545
 546    #[inline]
 547    fn add_constant_in_place<CS: ConstraintSystem<ConstraintF>>(
 548        &mut self,
 549        mut cs: CS,
 550        other: &Fp6<P>,
 551    ) -> Result<&mut Self, SynthesisError> {
 552        self.c0.add_constant_in_place(cs.ns(|| "c0"), &other.c0)?;
 553        self.c1.add_constant_in_place(cs.ns(|| "c1"), &other.c1)?;
 554        self.c2.add_constant_in_place(cs.ns(|| "c2"), &other.c2)?;
 555        Ok(self)
 556    }
 557
 558    /// Use the Toom-Cook-3x method to compute multiplication.
 559    #[inline]
 560    fn mul_by_constant<CS: ConstraintSystem<ConstraintF>>(
 561        &self,
 562        mut cs: CS,
 563        other: &Fp6<P>,
 564    ) -> Result<Self, SynthesisError> {
 565        // Uses Toom-Cook-3x multiplication from
 566        //
 567        // Reference:
 568        // "Multiplication and Squaring on Pairing-Friendly Fields"
 569        //    Devegili, OhEigeartaigh, Scott, Dahab
 570
 571        // v0 = a(0)b(0)   = a0 * b0
 572        let v0 = self.c0.mul_by_constant(cs.ns(|| "v0"), &other.c0)?;
 573
 574        // v1 = a(1)b(1)   = (a0 + a1 + a2)(b0 + b1 + b2)
 575        let v1 = {
 576            let mut v1_cs = cs.ns(|| "v1");
 577            let mut a0_plus_a1_plus_a2 = self
 578                .c0
 579                .add(v1_cs.ns(|| "a0 + a1"), &self.c1)?
 580                .add(v1_cs.ns(|| "a0 + a1 + a2"), &self.c2)?;
 581            let b0_plus_b1_plus_b2 = other.c0 + &other.c1 + &other.c2;
 582
 583            a0_plus_a1_plus_a2.mul_by_constant_in_place(
 584                v1_cs.ns(|| "(a0 + a1 + a2)*(b0 + b1 + b2)"),
 585                &b0_plus_b1_plus_b2,
 586            )?;
 587            a0_plus_a1_plus_a2
 588        };
 589
 590        // v2 = a(−1)b(−1) = (a0 − a1 + a2)(b0 − b1 + b2)
 591        let mut v2 = {
 592            let mut v2_cs = cs.ns(|| "v2");
 593            let mut a0_minus_a1_plus_a2 = self
 594                .c0
 595                .sub(v2_cs.ns(|| "sub1"), &self.c1)?
 596                .add(v2_cs.ns(|| "add2"), &self.c2)?;
 597            let b0_minus_b1_plus_b2 = other.c0 - &other.c1 + &other.c2;
 598            a0_minus_a1_plus_a2.mul_by_constant_in_place(
 599                v2_cs.ns(|| "(a0 - a1 + a2)*(b0 - b1 + b2)"),
 600                &b0_minus_b1_plus_b2,
 601            )?;
 602            a0_minus_a1_plus_a2
 603        };
 604
 605        // v3 = a(2)b(2)   = (a0 + 2a1 + 4a2)(b0 + 2b1 + 4b2)
 606        let mut v3 = {
 607            let mut v3_cs = cs.ns(|| "v3");
 608            let a1_double = self.c1.double(v3_cs.ns(|| "2a1"))?;
 609            let a2_quad = self
 610                .c2
 611                .double(v3_cs.ns(|| "2a2"))?
 612                .double(v3_cs.ns(|| "4a2"))?;
 613            let mut a0_plus_2_a1_plus_4_a2 = self
 614                .c0
 615                .add(v3_cs.ns(|| "a0 + 2a1"), &a1_double)?
 616                .add(v3_cs.ns(|| "a0 + 2a1 + 4a2"), &a2_quad)?;
 617
 618            let b1_double = other.c1.double();
 619            let b2_quad = other.c2.double().double();
 620            let b0_plus_2_b1_plus_4_b2 = other.c0 + &b1_double + &b2_quad;
 621
 622            a0_plus_2_a1_plus_4_a2.mul_by_constant_in_place(
 623                v3_cs.ns(|| "(a0 + 2a1 + 4a2)*(b0 + 2b1 + 4b2)"),
 624                &b0_plus_2_b1_plus_4_b2,
 625            )?;
 626            a0_plus_2_a1_plus_4_a2
 627        };
 628
 629        // v4 = a(∞)b(∞)   = a2 * b2
 630        let v4 = self.c2.mul_by_constant(cs.ns(|| "v4"), &other.c2)?;
 631
 632        let two = <P::Fp2Params as Fp2Parameters>::Fp::one().double();
 633        let six = two.double() + &two;
 634        let mut two_and_six = [two, six];
 635        algebra::fields::batch_inversion(&mut two_and_six);
 636        let (two_inverse, six_inverse) = (two_and_six[0], two_and_six[1]);
 637
 638        let mut half_v0 = v0.mul_by_fp_constant(cs.ns(|| "half_v0"), &two_inverse)?;
 639        let half_v1 = v1.mul_by_fp_constant(cs.ns(|| "half_v1"), &two_inverse)?;
 640        let mut one_sixth_v2 = v2.mul_by_fp_constant(cs.ns(|| "v2_by_6"), &six_inverse)?;
 641        let one_sixth_v3 = v3.mul_by_fp_constant_in_place(cs.ns(|| "v3_by_6"), &six_inverse)?;
 642        let two_v4 = v4.double(cs.ns(|| "2v4"))?;
 643
 644        // c0 = v0 + β((1/2)v0 − (1/2)v1 − (1/6)v2 + (1/6)v3 − 2v4)
 645        let c0 = {
 646            let mut c0_cs = cs.ns(|| "c0");
 647
 648            // No constraints, only get a linear combination back.
 649            let mut inner = half_v0
 650                .sub(c0_cs.ns(|| "sub1"), &half_v1)?
 651                .sub(c0_cs.ns(|| "sub2"), &one_sixth_v2)?
 652                .add(c0_cs.ns(|| "add3"), &one_sixth_v3)?
 653                .sub(c0_cs.ns(|| "sub4"), &two_v4)?;
 654            let non_residue_times_inner =
 655                inner.mul_by_constant_in_place(&mut c0_cs, &P::NONRESIDUE)?;
 656            v0.add(c0_cs.ns(|| "add5"), non_residue_times_inner)?
 657        };
 658
 659        // −(1/2)v0 + v1 − (1/3)v2 − (1/6)v3 + 2v4 + βv4
 660        let c1 = {
 661            let mut c1_cs = cs.ns(|| "c1");
 662            let one_third_v2 = one_sixth_v2.double_in_place(c1_cs.ns(|| "double1"))?;
 663            let non_residue_v4 =
 664                v4.mul_by_constant(c1_cs.ns(|| "mul_by_const1"), &P::NONRESIDUE)?;
 665
 666            half_v0
 667                .negate_in_place(c1_cs.ns(|| "neg1"))?
 668                .add(c1_cs.ns(|| "add1"), &v1)?
 669                .sub(c1_cs.ns(|| "sub2"), one_third_v2)?
 670                .sub(c1_cs.ns(|| "sub3"), &one_sixth_v3)?
 671                .add(c1_cs.ns(|| "add4"), &two_v4)?
 672                .add(c1_cs.ns(|| "add5"), &non_residue_v4)?
 673        };
 674
 675        // -v0 + (1/2)v1 + (1/2)v2 −v4
 676        let c2 = {
 677            let mut c2_cs = cs.ns(|| "c2");
 678            let half_v2 = v2.mul_by_fp_constant_in_place(c2_cs.ns(|| "half_v2"), &two_inverse)?;
 679            half_v1
 680                .add(c2_cs.ns(|| "add1"), half_v2)?
 681                .sub(c2_cs.ns(|| "sub2"), &v4)?
 682                .sub(c2_cs.ns(|| "sub3"), &v0)?
 683        };
 684
 685        Ok(Self::new(c0, c1, c2))
 686    }
 687
 688    fn frobenius_map<CS: ConstraintSystem<ConstraintF>>(
 689        &self,
 690        cs: CS,
 691        power: usize,
 692    ) -> Result<Self, SynthesisError> {
 693        let mut result = self.clone();
 694        result.frobenius_map_in_place(cs, power)?;
 695        Ok(result)
 696    }
 697
 698    fn frobenius_map_in_place<CS: ConstraintSystem<ConstraintF>>(
 699        &mut self,
 700        mut cs: CS,
 701        power: usize,
 702    ) -> Result<&mut Self, SynthesisError> {
 703        self.c0.frobenius_map_in_place(&mut cs.ns(|| "c0"), power)?;
 704        self.c1.frobenius_map_in_place(&mut cs.ns(|| "c1"), power)?;
 705        self.c2.frobenius_map_in_place(&mut cs.ns(|| "c2"), power)?;
 706
 707        self.c1.mul_by_constant_in_place(
 708            cs.ns(|| "c1_power"),
 709            &P::FROBENIUS_COEFF_FP6_C1[power % 6],
 710        )?;
 711        self.c2.mul_by_constant_in_place(
 712            cs.ns(|| "c2_power"),
 713            &P::FROBENIUS_COEFF_FP6_C2[power % 6],
 714        )?;
 715
 716        Ok(self)
 717    }
 718
 719    fn cost_of_mul() -> usize {
 720        5 * Fp2Gadget::<P, ConstraintF>::cost_of_mul()
 721    }
 722
 723    fn cost_of_mul_equals() -> usize {
 724        6 * Fp2Gadget::<P, ConstraintF>::cost_of_mul()
 725    }
 726}
 727
 728impl<P, ConstraintF: PrimeField> PartialEq for Fp6Gadget<P, ConstraintF>
 729where
 730    P: Fp6Parameters,
 731    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 732{
 733    fn eq(&self, other: &Self) -> bool {
 734        self.c0 == other.c0 && self.c1 == other.c1 && self.c2 == other.c2
 735    }
 736}
 737
 738impl<P, ConstraintF: PrimeField> Eq for Fp6Gadget<P, ConstraintF>
 739where
 740    P: Fp6Parameters,
 741    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 742{
 743}
 744
 745impl<P, ConstraintF: PrimeField> EqGadget<ConstraintF> for Fp6Gadget<P, ConstraintF>
 746where
 747    P: Fp6Parameters,
 748    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 749{
 750}
 751
 752impl<P, ConstraintF: PrimeField> ConditionalEqGadget<ConstraintF> for Fp6Gadget<P, ConstraintF>
 753where
 754    P: Fp6Parameters,
 755    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 756{
 757    #[inline]
 758    fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>(
 759        &self,
 760        mut cs: CS,
 761        other: &Self,
 762        condition: &Boolean,
 763    ) -> Result<(), SynthesisError> {
 764        self.c0
 765            .conditional_enforce_equal(&mut cs.ns(|| "c0"), &other.c0, condition)?;
 766        self.c1
 767            .conditional_enforce_equal(&mut cs.ns(|| "c1"), &other.c1, condition)?;
 768        self.c2
 769            .conditional_enforce_equal(&mut cs.ns(|| "c2"), &other.c2, condition)?;
 770        Ok(())
 771    }
 772
 773    fn cost() -> usize {
 774        3 * <Fp2Gadget<P, ConstraintF> as ConditionalEqGadget<ConstraintF>>::cost()
 775    }
 776}
 777
 778impl<P, ConstraintF: PrimeField> NEqGadget<ConstraintF> for Fp6Gadget<P, ConstraintF>
 779where
 780    P: Fp6Parameters,
 781    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 782{
 783    #[inline]
 784    fn enforce_not_equal<CS: ConstraintSystem<ConstraintF>>(
 785        &self,
 786        mut cs: CS,
 787        other: &Self,
 788    ) -> Result<(), SynthesisError> {
 789        self.c0.enforce_not_equal(&mut cs.ns(|| "c0"), &other.c0)?;
 790        self.c1.enforce_not_equal(&mut cs.ns(|| "c1"), &other.c1)?;
 791        self.c2.enforce_not_equal(&mut cs.ns(|| "c2"), &other.c2)?;
 792        Ok(())
 793    }
 794
 795    fn cost() -> usize {
 796        3 * <Fp2Gadget<P, ConstraintF> as NEqGadget<ConstraintF>>::cost()
 797    }
 798}
 799
 800impl<P, ConstraintF: PrimeField> ToBitsGadget<ConstraintF> for Fp6Gadget<P, ConstraintF>
 801where
 802    P: Fp6Parameters,
 803    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 804{
 805    fn to_bits<CS: ConstraintSystem<ConstraintF>>(
 806        &self,
 807        mut cs: CS,
 808    ) -> Result<Vec<Boolean>, SynthesisError> {
 809        let mut c0 = self.c0.to_bits(cs.ns(|| "c0"))?;
 810        let mut c1 = self.c1.to_bits(cs.ns(|| "c1"))?;
 811        let mut c2 = self.c2.to_bits(cs.ns(|| "c2"))?;
 812
 813        c0.append(&mut c1);
 814        c0.append(&mut c2);
 815
 816        Ok(c0)
 817    }
 818
 819    fn to_non_unique_bits<CS: ConstraintSystem<ConstraintF>>(
 820        &self,
 821        mut cs: CS,
 822    ) -> Result<Vec<Boolean>, SynthesisError> {
 823        let mut c0 = self.c0.to_non_unique_bits(cs.ns(|| "c0"))?;
 824        let mut c1 = self.c1.to_non_unique_bits(cs.ns(|| "c1"))?;
 825        let mut c2 = self.c2.to_non_unique_bits(cs.ns(|| "c2"))?;
 826
 827        c0.append(&mut c1);
 828        c0.append(&mut c2);
 829
 830        Ok(c0)
 831    }
 832}
 833
 834impl<P, ConstraintF: PrimeField> ToBytesGadget<ConstraintF> for Fp6Gadget<P, ConstraintF>
 835where
 836    P: Fp6Parameters,
 837    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 838{
 839    fn to_bytes<CS: ConstraintSystem<ConstraintF>>(
 840        &self,
 841        mut cs: CS,
 842    ) -> Result<Vec<UInt8>, SynthesisError> {
 843        let mut c0 = self.c0.to_bytes(cs.ns(|| "c0"))?;
 844        let mut c1 = self.c1.to_bytes(cs.ns(|| "c1"))?;
 845        let mut c2 = self.c2.to_bytes(cs.ns(|| "c2"))?;
 846
 847        c0.append(&mut c1);
 848        c0.append(&mut c2);
 849
 850        Ok(c0)
 851    }
 852
 853    fn to_non_unique_bytes<CS: ConstraintSystem<ConstraintF>>(
 854        &self,
 855        mut cs: CS,
 856    ) -> Result<Vec<UInt8>, SynthesisError> {
 857        let mut c0 = self.c0.to_non_unique_bytes(cs.ns(|| "c0"))?;
 858        let mut c1 = self.c1.to_non_unique_bytes(cs.ns(|| "c1"))?;
 859        let mut c2 = self.c2.to_non_unique_bytes(cs.ns(|| "c2"))?;
 860
 861        c0.append(&mut c1);
 862        c0.append(&mut c2);
 863
 864        Ok(c0)
 865    }
 866}
 867
 868impl<P, ConstraintF: PrimeField> Clone for Fp6Gadget<P, ConstraintF>
 869where
 870    P: Fp6Parameters,
 871    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 872{
 873    fn clone(&self) -> Self {
 874        Self::new(self.c0.clone(), self.c1.clone(), self.c2.clone())
 875    }
 876}
 877
 878impl<P, ConstraintF: PrimeField> CondSelectGadget<ConstraintF> for Fp6Gadget<P, ConstraintF>
 879where
 880    P: Fp6Parameters,
 881    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 882{
 883    #[inline]
 884    fn conditionally_select<CS: ConstraintSystem<ConstraintF>>(
 885        mut cs: CS,
 886        cond: &Boolean,
 887        true_value: &Self,
 888        false_value: &Self,
 889    ) -> Result<Self, SynthesisError> {
 890        let c0 = Fp2Gadget::<P, ConstraintF>::conditionally_select(
 891            &mut cs.ns(|| "c0"),
 892            cond,
 893            &true_value.c0,
 894            &false_value.c0,
 895        )?;
 896        let c1 = Fp2Gadget::<P, ConstraintF>::conditionally_select(
 897            &mut cs.ns(|| "c1"),
 898            cond,
 899            &true_value.c1,
 900            &false_value.c1,
 901        )?;
 902        let c2 = Fp2Gadget::<P, ConstraintF>::conditionally_select(
 903            &mut cs.ns(|| "c2"),
 904            cond,
 905            &true_value.c2,
 906            &false_value.c2,
 907        )?;
 908
 909        Ok(Self::new(c0, c1, c2))
 910    }
 911
 912    fn cost() -> usize {
 913        3 * <Fp2Gadget<P, ConstraintF> as CondSelectGadget<ConstraintF>>::cost()
 914    }
 915}
 916
 917impl<P, ConstraintF: PrimeField> TwoBitLookupGadget<ConstraintF> for Fp6Gadget<P, ConstraintF>
 918where
 919    P: Fp6Parameters,
 920    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 921{
 922    type TableConstant = Fp6<P>;
 923    fn two_bit_lookup<CS: ConstraintSystem<ConstraintF>>(
 924        mut cs: CS,
 925        b: &[Boolean],
 926        c: &[Self::TableConstant],
 927    ) -> Result<Self, SynthesisError> {
 928        let c0s = c.iter().map(|f| f.c0).collect::<Vec<_>>();
 929        let c1s = c.iter().map(|f| f.c1).collect::<Vec<_>>();
 930        let c2s = c.iter().map(|f| f.c2).collect::<Vec<_>>();
 931        let c0 = Fp2Gadget::<P, ConstraintF>::two_bit_lookup(cs.ns(|| "Lookup c0"), b, &c0s)?;
 932        let c1 = Fp2Gadget::<P, ConstraintF>::two_bit_lookup(cs.ns(|| "Lookup c1"), b, &c1s)?;
 933        let c2 = Fp2Gadget::<P, ConstraintF>::two_bit_lookup(cs.ns(|| "Lookup c2"), b, &c2s)?;
 934        Ok(Self::new(c0, c1, c2))
 935    }
 936
 937    fn cost() -> usize {
 938        3 * <Fp2Gadget<P, ConstraintF> as TwoBitLookupGadget<ConstraintF>>::cost()
 939    }
 940}
 941
 942impl<P, ConstraintF: PrimeField> ThreeBitCondNegLookupGadget<ConstraintF>
 943    for Fp6Gadget<P, ConstraintF>
 944where
 945    P: Fp6Parameters,
 946    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 947{
 948    type TableConstant = Fp6<P>;
 949
 950    fn three_bit_cond_neg_lookup<CS: ConstraintSystem<ConstraintF>>(
 951        mut cs: CS,
 952        b: &[Boolean],
 953        b0b1: &Boolean,
 954        c: &[Self::TableConstant],
 955    ) -> Result<Self, SynthesisError> {
 956        let c0s = c.iter().map(|f| f.c0).collect::<Vec<_>>();
 957        let c1s = c.iter().map(|f| f.c1).collect::<Vec<_>>();
 958        let c2s = c.iter().map(|f| f.c2).collect::<Vec<_>>();
 959        let c0 = Fp2Gadget::<P, ConstraintF>::three_bit_cond_neg_lookup(
 960            cs.ns(|| "Lookup c0"),
 961            b,
 962            b0b1,
 963            &c0s,
 964        )?;
 965        let c1 = Fp2Gadget::<P, ConstraintF>::three_bit_cond_neg_lookup(
 966            cs.ns(|| "Lookup c1"),
 967            b,
 968            b0b1,
 969            &c1s,
 970        )?;
 971        let c2 = Fp2Gadget::<P, ConstraintF>::three_bit_cond_neg_lookup(
 972            cs.ns(|| "Lookup c2"),
 973            b,
 974            b0b1,
 975            &c2s,
 976        )?;
 977        Ok(Self::new(c0, c1, c2))
 978    }
 979
 980    fn cost() -> usize {
 981        3 * <Fp2Gadget<P, ConstraintF> as ThreeBitCondNegLookupGadget<ConstraintF>>::cost()
 982    }
 983}
 984
 985impl<P, ConstraintF: PrimeField> AllocGadget<Fp6<P>, ConstraintF> for Fp6Gadget<P, ConstraintF>
 986where
 987    P: Fp6Parameters,
 988    P::Fp2Params: Fp2Parameters<Fp = ConstraintF>,
 989{
 990    #[inline]
 991    fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>(
 992        mut cs: CS,
 993        t: T,
 994    ) -> Result<Self, SynthesisError>
 995    where
 996        T: Borrow<Fp6<P>>,
 997    {
 998        Self::zero(cs.ns(|| "zero"))?.add_constant(cs.ns(|| "add constant"), t.borrow())
 999    }
1000
1001    #[inline]
1002    fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
1003        mut cs: CS,
1004        value_gen: F,
1005    ) -> Result<Self, SynthesisError>
1006    where
1007        F: FnOnce() -> Result<T, SynthesisError>,
1008        T: Borrow<Fp6<P>>,
1009    {
1010        let (c0, c1, c2) = match value_gen() {
1011            Ok(fe) => {
1012                let fe = *fe.borrow();
1013                (Ok(fe.c0), Ok(fe.c1), Ok(fe.c2))
1014            }
1015            _ => (
1016                Err(SynthesisError::AssignmentMissing),
1017                Err(SynthesisError::AssignmentMissing),
1018                Err(SynthesisError::AssignmentMissing),
1019            ),
1020        };
1021
1022        let c0 = Fp2Gadget::<P, ConstraintF>::alloc(&mut cs.ns(|| "c0"), || c0)?;
1023        let c1 = Fp2Gadget::<P, ConstraintF>::alloc(&mut cs.ns(|| "c1"), || c1)?;
1024        let c2 = Fp2Gadget::<P, ConstraintF>::alloc(&mut cs.ns(|| "c2"), || c2)?;
1025        Ok(Self::new(c0, c1, c2))
1026    }
1027
1028    #[inline]
1029    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
1030        mut cs: CS,
1031        value_gen: F,
1032    ) -> Result<Self, SynthesisError>
1033    where
1034        F: FnOnce() -> Result<T, SynthesisError>,
1035        T: Borrow<Fp6<P>>,
1036    {
1037        let (c0, c1, c2) = match value_gen() {
1038            Ok(fe) => {
1039                let fe = *fe.borrow();
1040                (Ok(fe.c0), Ok(fe.c1), Ok(fe.c2))
1041            }
1042            _ => (
1043                Err(SynthesisError::AssignmentMissing),
1044                Err(SynthesisError::AssignmentMissing),
1045                Err(SynthesisError::AssignmentMissing),
1046            ),
1047        };
1048
1049        let c0 = Fp2Gadget::<P, ConstraintF>::alloc_input(&mut cs.ns(|| "c0"), || c0)?;
1050        let c1 = Fp2Gadget::<P, ConstraintF>::alloc_input(&mut cs.ns(|| "c1"), || c1)?;
1051        let c2 = Fp2Gadget::<P, ConstraintF>::alloc_input(&mut cs.ns(|| "c2"), || c2)?;
1052        Ok(Self::new(c0, c1, c2))
1053    }
1054}