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