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