1use ark_ec::mnt6::{
2 g2::{AteAdditionCoefficients, AteDoubleCoefficients},
3 G1Prepared, G2Prepared, MNT6Config,
4};
5use ark_ff::Field;
6use ark_relations::r1cs::{Namespace, SynthesisError};
7
8use crate::{
9 convert::ToBytesGadget,
10 fields::{fp::FpVar, fp3::Fp3Var, FieldVar},
11 groups::curves::short_weierstrass::ProjectiveVar,
12 pairing::mnt6::PairingVar,
13 prelude::*,
14 Vec,
15};
16use core::borrow::Borrow;
17use educe::Educe;
18
19pub type G1Var<P> = ProjectiveVar<<P as MNT6Config>::G1Config, FpVar<<P as MNT6Config>::Fp>>;
21
22pub type G2Var<P> = ProjectiveVar<<P as MNT6Config>::G2Config, Fp3G<P>>;
24
25#[derive(Educe)]
28#[educe(Clone, Debug)]
29pub struct G1PreparedVar<P: MNT6Config> {
30 #[doc(hidden)]
31 pub x: FpVar<P::Fp>,
32 #[doc(hidden)]
33 pub y: FpVar<P::Fp>,
34 #[doc(hidden)]
35 pub x_twist: Fp3Var<P::Fp3Config>,
36 #[doc(hidden)]
37 pub y_twist: Fp3Var<P::Fp3Config>,
38}
39
40impl<P: MNT6Config> G1PreparedVar<P> {
41 pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
44 let x = self.x.value()?;
45 let y = self.y.value()?;
46 let x_twist = self.x_twist.value()?;
47 let y_twist = self.y_twist.value()?;
48 Ok(G1Prepared {
49 x,
50 y,
51 x_twist,
52 y_twist,
53 })
54 }
55
56 #[tracing::instrument(target = "r1cs")]
58 pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
59 let q = q.to_affine()?;
60 let zero = FpVar::<P::Fp>::zero();
61 let x_twist = Fp3Var::new(q.x.clone(), zero.clone(), zero.clone()) * P::TWIST;
62 let y_twist = Fp3Var::new(q.y.clone(), zero.clone(), zero) * P::TWIST;
63 let result = G1PreparedVar {
64 x: q.x,
65 y: q.y,
66 x_twist,
67 y_twist,
68 };
69 Ok(result)
70 }
71}
72
73impl<P: MNT6Config> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
74 #[tracing::instrument(target = "r1cs", skip(cs, f))]
75 fn new_variable<T: Borrow<G1Prepared<P>>>(
76 cs: impl Into<Namespace<P::Fp>>,
77 f: impl FnOnce() -> Result<T, SynthesisError>,
78 mode: AllocationMode,
79 ) -> Result<Self, SynthesisError> {
80 let ns = cs.into();
81 let cs = ns.cs();
82
83 let g1_prep = f().map(|b| *b.borrow());
84
85 let x = FpVar::new_variable(ark_relations::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?;
86 let y = FpVar::new_variable(ark_relations::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?;
87 let x_twist = Fp3Var::new_variable(
88 ark_relations::ns!(cs, "x_twist"),
89 || g1_prep.map(|g| g.x_twist),
90 mode,
91 )?;
92 let y_twist = Fp3Var::new_variable(
93 ark_relations::ns!(cs, "y_twist"),
94 || g1_prep.map(|g| g.y_twist),
95 mode,
96 )?;
97 Ok(Self {
98 x,
99 y,
100 x_twist,
101 y_twist,
102 })
103 }
104}
105
106impl<P: MNT6Config> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
107 #[inline]
108 #[tracing::instrument(target = "r1cs")]
109 fn to_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
110 let mut x = self.x.to_bytes_le()?;
111 let mut y = self.y.to_bytes_le()?;
112 let mut x_twist = self.x_twist.to_bytes_le()?;
113 let mut y_twist = self.y_twist.to_bytes_le()?;
114
115 x.append(&mut y);
116 x.append(&mut x_twist);
117 x.append(&mut y_twist);
118 Ok(x)
119 }
120
121 #[tracing::instrument(target = "r1cs")]
122 fn to_non_unique_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
123 let mut x = self.x.to_non_unique_bytes_le()?;
124 let mut y = self.y.to_non_unique_bytes_le()?;
125 let mut x_twist = self.x_twist.to_non_unique_bytes_le()?;
126 let mut y_twist = self.y_twist.to_non_unique_bytes_le()?;
127
128 x.append(&mut y);
129 x.append(&mut x_twist);
130 x.append(&mut y_twist);
131 Ok(x)
132 }
133}
134
135type Fp3G<P> = Fp3Var<<P as MNT6Config>::Fp3Config>;
136
137#[derive(Educe)]
140#[educe(Clone, Debug)]
141pub struct G2PreparedVar<P: MNT6Config> {
142 #[doc(hidden)]
143 pub x: Fp3Var<P::Fp3Config>,
144 #[doc(hidden)]
145 pub y: Fp3Var<P::Fp3Config>,
146 #[doc(hidden)]
147 pub x_over_twist: Fp3Var<P::Fp3Config>,
148 #[doc(hidden)]
149 pub y_over_twist: Fp3Var<P::Fp3Config>,
150 #[doc(hidden)]
151 pub double_coefficients: Vec<AteDoubleCoefficientsVar<P>>,
152 #[doc(hidden)]
153 pub addition_coefficients: Vec<AteAdditionCoefficientsVar<P>>,
154}
155
156impl<P: MNT6Config> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
157 #[tracing::instrument(target = "r1cs", skip(cs, f))]
158 fn new_variable<T: Borrow<G2Prepared<P>>>(
159 cs: impl Into<Namespace<P::Fp>>,
160 f: impl FnOnce() -> Result<T, SynthesisError>,
161 mode: AllocationMode,
162 ) -> Result<Self, SynthesisError> {
163 let ns = cs.into();
164 let cs = ns.cs();
165
166 let g2_prep = f().map(|b| b.borrow().clone());
167 let g2 = g2_prep.as_ref().map_err(|e| *e);
168
169 let x = Fp3Var::new_variable(ark_relations::ns!(cs, "x"), || g2.map(|g| g.x), mode)?;
170 let y = Fp3Var::new_variable(ark_relations::ns!(cs, "y"), || g2.map(|g| g.y), mode)?;
171 let x_over_twist = Fp3Var::new_variable(
172 ark_relations::ns!(cs, "x_over_twist"),
173 || g2.map(|g| g.x_over_twist),
174 mode,
175 )?;
176 let y_over_twist = Fp3Var::new_variable(
177 ark_relations::ns!(cs, "y_over_twist"),
178 || g2.map(|g| g.y_over_twist),
179 mode,
180 )?;
181 let double_coefficients = Vec::new_variable(
182 ark_relations::ns!(cs, "double coeffs"),
183 || g2.map(|g| g.double_coefficients.clone()),
184 mode,
185 )?;
186 let addition_coefficients = Vec::new_variable(
187 ark_relations::ns!(cs, "add coeffs"),
188 || g2.map(|g| g.addition_coefficients.clone()),
189 mode,
190 )?;
191 Ok(Self {
192 x,
193 y,
194 x_over_twist,
195 y_over_twist,
196 double_coefficients,
197 addition_coefficients,
198 })
199 }
200}
201
202impl<P: MNT6Config> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
203 #[inline]
204 #[tracing::instrument(target = "r1cs")]
205 fn to_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
206 let mut x = self.x.to_bytes_le()?;
207 let mut y = self.y.to_bytes_le()?;
208 let mut x_over_twist = self.x_over_twist.to_bytes_le()?;
209 let mut y_over_twist = self.y_over_twist.to_bytes_le()?;
210
211 x.append(&mut y);
212 x.append(&mut x_over_twist);
213 x.append(&mut y_over_twist);
214
215 for coeff in self.double_coefficients.iter() {
216 x.extend_from_slice(&coeff.to_bytes_le()?);
217 }
218 for coeff in self.addition_coefficients.iter() {
219 x.extend_from_slice(&coeff.to_bytes_le()?);
220 }
221 Ok(x)
222 }
223
224 #[tracing::instrument(target = "r1cs")]
225 fn to_non_unique_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
226 let mut x = self.x.to_non_unique_bytes_le()?;
227 let mut y = self.y.to_non_unique_bytes_le()?;
228 let mut x_over_twist = self.x_over_twist.to_non_unique_bytes_le()?;
229 let mut y_over_twist = self.y_over_twist.to_non_unique_bytes_le()?;
230
231 x.append(&mut y);
232 x.append(&mut x_over_twist);
233 x.append(&mut y_over_twist);
234
235 for coeff in self.double_coefficients.iter() {
236 x.extend_from_slice(&coeff.to_non_unique_bytes_le()?);
237 }
238 for coeff in self.addition_coefficients.iter() {
239 x.extend_from_slice(&coeff.to_non_unique_bytes_le()?);
240 }
241 Ok(x)
242 }
243}
244
245impl<P: MNT6Config> G2PreparedVar<P> {
246 pub fn value(&self) -> Result<G2Prepared<P>, SynthesisError> {
249 let x = self.x.value()?;
250 let y = self.y.value()?;
251 let x_over_twist = self.x_over_twist.value()?;
252 let y_over_twist = self.y_over_twist.value()?;
253 let double_coefficients = self
254 .double_coefficients
255 .iter()
256 .map(|coeff| coeff.value())
257 .collect::<Result<Vec<_>, SynthesisError>>()?;
258 let addition_coefficients = self
259 .addition_coefficients
260 .iter()
261 .map(|coeff| coeff.value())
262 .collect::<Result<Vec<_>, SynthesisError>>()?;
263 Ok(G2Prepared {
264 x,
265 y,
266 x_over_twist,
267 y_over_twist,
268 double_coefficients,
269 addition_coefficients,
270 })
271 }
272
273 #[tracing::instrument(target = "r1cs")]
275 pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
276 let q = q.to_affine()?;
277 let twist_inv = P::TWIST.inverse().unwrap();
278
279 let mut g2p = G2PreparedVar {
280 x: q.x.clone(),
281 y: q.y.clone(),
282 x_over_twist: &q.x * twist_inv,
283 y_over_twist: &q.y * twist_inv,
284 double_coefficients: vec![],
285 addition_coefficients: vec![],
286 };
287
288 let mut r = G2ProjectiveExtendedVar {
289 x: q.x.clone(),
290 y: q.y.clone(),
291 z: Fp3G::<P>::one(),
292 t: Fp3G::<P>::one(),
293 };
294
295 for bit in P::ATE_LOOP_COUNT.iter().skip(1) {
296 let (r2, coeff) = PairingVar::<P>::doubling_step_for_flipped_miller_loop(&r)?;
297 g2p.double_coefficients.push(coeff);
298 r = r2;
299
300 let add_coeff;
301 let r_temp;
302 match bit {
303 1 => {
304 (r_temp, add_coeff) =
305 PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop(
306 &q.x, &q.y, &r,
307 )?;
308 },
309 -1 => {
310 (r_temp, add_coeff) =
311 PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop(
312 &q.x,
313 &q.y.negate()?,
314 &r,
315 )?;
316 },
317 _ => continue,
318 }
319 g2p.addition_coefficients.push(add_coeff);
320 r = r_temp;
321 }
322
323 if P::ATE_IS_LOOP_COUNT_NEG {
324 let rz_inv = r.z.inverse()?;
325 let rz2_inv = rz_inv.square()?;
326 let rz3_inv = &rz_inv * &rz2_inv;
327
328 let minus_r_affine_x = &r.x * &rz2_inv;
329 let minus_r_affine_y = r.y.negate()? * &rz3_inv;
330
331 let add_result = PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop(
332 &minus_r_affine_x,
333 &minus_r_affine_y,
334 &r,
335 )?;
336 g2p.addition_coefficients.push(add_result.1);
337 }
338
339 Ok(g2p)
340 }
341}
342
343#[doc(hidden)]
344#[derive(Educe)]
345#[educe(Clone, Debug)]
346pub struct AteDoubleCoefficientsVar<P: MNT6Config> {
347 pub c_h: Fp3Var<P::Fp3Config>,
348 pub c_4c: Fp3Var<P::Fp3Config>,
349 pub c_j: Fp3Var<P::Fp3Config>,
350 pub c_l: Fp3Var<P::Fp3Config>,
351}
352
353impl<P: MNT6Config> AllocVar<AteDoubleCoefficients<P>, P::Fp> for AteDoubleCoefficientsVar<P> {
354 #[tracing::instrument(target = "r1cs", skip(cs, f))]
355 fn new_variable<T: Borrow<AteDoubleCoefficients<P>>>(
356 cs: impl Into<Namespace<P::Fp>>,
357 f: impl FnOnce() -> Result<T, SynthesisError>,
358 mode: AllocationMode,
359 ) -> Result<Self, SynthesisError> {
360 let ns = cs.into();
361 let cs = ns.cs();
362
363 let c_prep = f().map(|c| c.borrow().clone());
364 let c = c_prep.as_ref().map_err(|e| *e);
365
366 let c_h = Fp3Var::new_variable(ark_relations::ns!(cs, "c_h"), || c.map(|c| c.c_h), mode)?;
367 let c_4c =
368 Fp3Var::new_variable(ark_relations::ns!(cs, "c_4c"), || c.map(|c| c.c_4c), mode)?;
369 let c_j = Fp3Var::new_variable(ark_relations::ns!(cs, "c_j"), || c.map(|c| c.c_j), mode)?;
370 let c_l = Fp3Var::new_variable(ark_relations::ns!(cs, "c_l"), || c.map(|c| c.c_l), mode)?;
371 Ok(Self {
372 c_h,
373 c_4c,
374 c_j,
375 c_l,
376 })
377 }
378}
379
380impl<P: MNT6Config> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> {
381 #[inline]
382 #[tracing::instrument(target = "r1cs")]
383 fn to_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
384 let mut c_h = self.c_h.to_bytes_le()?;
385 let mut c_4c = self.c_4c.to_bytes_le()?;
386 let mut c_j = self.c_j.to_bytes_le()?;
387 let mut c_l = self.c_l.to_bytes_le()?;
388
389 c_h.append(&mut c_4c);
390 c_h.append(&mut c_j);
391 c_h.append(&mut c_l);
392 Ok(c_h)
393 }
394
395 #[tracing::instrument(target = "r1cs")]
396 fn to_non_unique_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
397 let mut c_h = self.c_h.to_non_unique_bytes_le()?;
398 let mut c_4c = self.c_4c.to_non_unique_bytes_le()?;
399 let mut c_j = self.c_j.to_non_unique_bytes_le()?;
400 let mut c_l = self.c_l.to_non_unique_bytes_le()?;
401
402 c_h.append(&mut c_4c);
403 c_h.append(&mut c_j);
404 c_h.append(&mut c_l);
405 Ok(c_h)
406 }
407}
408
409impl<P: MNT6Config> AteDoubleCoefficientsVar<P> {
410 pub fn value(&self) -> Result<AteDoubleCoefficients<P>, SynthesisError> {
413 let c_h = self.c_h.value()?;
414 let c_4c = self.c_4c.value()?;
415 let c_j = self.c_j.value()?;
416 let c_l = self.c_l.value()?;
417 Ok(AteDoubleCoefficients {
418 c_h,
419 c_4c,
420 c_j,
421 c_l,
422 })
423 }
424}
425
426#[doc(hidden)]
427#[derive(Educe)]
428#[educe(Clone, Debug)]
429pub struct AteAdditionCoefficientsVar<P: MNT6Config> {
430 pub c_l1: Fp3Var<P::Fp3Config>,
431 pub c_rz: Fp3Var<P::Fp3Config>,
432}
433
434impl<P: MNT6Config> AllocVar<AteAdditionCoefficients<P>, P::Fp> for AteAdditionCoefficientsVar<P> {
435 #[tracing::instrument(target = "r1cs", skip(cs, f))]
436 fn new_variable<T: Borrow<AteAdditionCoefficients<P>>>(
437 cs: impl Into<Namespace<P::Fp>>,
438 f: impl FnOnce() -> Result<T, SynthesisError>,
439 mode: AllocationMode,
440 ) -> Result<Self, SynthesisError> {
441 let ns = cs.into();
442 let cs = ns.cs();
443
444 let c_prep = f().map(|c| c.borrow().clone());
445 let c = c_prep.as_ref().map_err(|e| *e);
446
447 let c_l1 =
448 Fp3Var::new_variable(ark_relations::ns!(cs, "c_l1"), || c.map(|c| c.c_l1), mode)?;
449 let c_rz =
450 Fp3Var::new_variable(ark_relations::ns!(cs, "c_rz"), || c.map(|c| c.c_rz), mode)?;
451 Ok(Self { c_l1, c_rz })
452 }
453}
454
455impl<P: MNT6Config> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> {
456 #[inline]
457 #[tracing::instrument(target = "r1cs")]
458 fn to_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
459 let mut c_l1 = self.c_l1.to_bytes_le()?;
460 let mut c_rz = self.c_rz.to_bytes_le()?;
461
462 c_l1.append(&mut c_rz);
463 Ok(c_l1)
464 }
465
466 #[tracing::instrument(target = "r1cs")]
467 fn to_non_unique_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
468 let mut c_l1 = self.c_l1.to_non_unique_bytes_le()?;
469 let mut c_rz = self.c_rz.to_non_unique_bytes_le()?;
470
471 c_l1.append(&mut c_rz);
472 Ok(c_l1)
473 }
474}
475
476impl<P: MNT6Config> AteAdditionCoefficientsVar<P> {
477 pub fn value(&self) -> Result<AteAdditionCoefficients<P>, SynthesisError> {
480 let c_l1 = self.c_l1.value()?;
481 let c_rz = self.c_rz.value()?;
482 Ok(AteAdditionCoefficients { c_l1, c_rz })
483 }
484}
485
486#[doc(hidden)]
487pub struct G2ProjectiveExtendedVar<P: MNT6Config> {
488 pub x: Fp3Var<P::Fp3Config>,
489 pub y: Fp3Var<P::Fp3Config>,
490 pub z: Fp3Var<P::Fp3Config>,
491 pub t: Fp3Var<P::Fp3Config>,
492}