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