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