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