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