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}