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