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