ark-r1cs-std/r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs
r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rsRaw
1use algebra::{
2 curves::mnt6::{
3 g2::{AteAdditionCoefficients, AteDoubleCoefficients},
4 G1Prepared, G2Prepared, MNT6Parameters,
5 },
6 Field,
7};
8use r1cs_core::{ConstraintSystem, SynthesisError};
9
10use crate::{
11 fields::{fp::FpGadget, fp3::Fp3Gadget, FieldGadget},
12 groups::curves::short_weierstrass::AffineGadget,
13 pairing::mnt6::PairingGadget,
14 prelude::*,
15 Vec,
16};
17
18pub type G1Gadget<P> = AffineGadget<
19 <P as MNT6Parameters>::G1Parameters,
20 <P as MNT6Parameters>::Fp,
21 FpGadget<<P as MNT6Parameters>::Fp>,
22>;
23
24pub type G2Gadget<P> =
25 AffineGadget<<P as MNT6Parameters>::G2Parameters, <P as MNT6Parameters>::Fp, Fp3G<P>>;
26
27#[derive(Derivative)]
28#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
29pub struct G1PreparedGadget<P: MNT6Parameters> {
30 pub x: FpGadget<P::Fp>,
31 pub y: FpGadget<P::Fp>,
32 pub x_twist: Fp3Gadget<P::Fp3Params, P::Fp>,
33 pub y_twist: Fp3Gadget<P::Fp3Params, P::Fp>,
34}
35
36impl<P: MNT6Parameters> G1PreparedGadget<P> {
37 pub fn get_value(&self) -> Option<G1Prepared<P>> {
38 match (
39 self.x.get_value(),
40 self.y.get_value(),
41 self.x_twist.get_value(),
42 self.y_twist.get_value(),
43 ) {
44 (Some(x), Some(y), Some(x_twist), Some(y_twist)) => Some(G1Prepared {
45 x,
46 y,
47 x_twist,
48 y_twist,
49 }),
50 _ => None,
51 }
52 }
53
54 pub fn from_affine<CS: ConstraintSystem<P::Fp>>(
55 mut cs: CS,
56 q: &G1Gadget<P>,
57 ) -> Result<Self, SynthesisError> {
58 let x_twist = Fp3Gadget::new(
59 q.x.mul_by_constant(cs.ns(|| "g1.x * twist.c0"), &P::TWIST.c0)?,
60 q.x.mul_by_constant(cs.ns(|| "g1.x * twist.c1"), &P::TWIST.c1)?,
61 q.x.mul_by_constant(cs.ns(|| "g1.x * twist.c2"), &P::TWIST.c2)?,
62 );
63 let y_twist = Fp3Gadget::new(
64 q.y.mul_by_constant(cs.ns(|| "g1.y * twist.c0"), &P::TWIST.c0)?,
65 q.y.mul_by_constant(cs.ns(|| "g1.y * twist.c1"), &P::TWIST.c1)?,
66 q.y.mul_by_constant(cs.ns(|| "g1.y * twist.c2"), &P::TWIST.c2)?,
67 );
68 Ok(G1PreparedGadget {
69 x: q.x.clone(),
70 y: q.y.clone(),
71 x_twist,
72 y_twist,
73 })
74 }
75}
76
77impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G1PreparedGadget<P> {
78 #[inline]
79 fn to_bytes<CS: ConstraintSystem<P::Fp>>(
80 &self,
81 mut cs: CS,
82 ) -> Result<Vec<UInt8>, SynthesisError> {
83 let mut x = self.x.to_bytes(&mut cs.ns(|| "x to bytes"))?;
84 let mut y = self.y.to_bytes(&mut cs.ns(|| "y to bytes"))?;
85 let mut x_twist = self.x_twist.to_bytes(&mut cs.ns(|| "x_twist to bytes"))?;
86 let mut y_twist = self.y_twist.to_bytes(&mut cs.ns(|| "y_twist to bytes"))?;
87
88 x.append(&mut y);
89 x.append(&mut x_twist);
90 x.append(&mut y_twist);
91 Ok(x)
92 }
93
94 fn to_non_unique_bytes<CS: ConstraintSystem<P::Fp>>(
95 &self,
96 mut cs: CS,
97 ) -> Result<Vec<UInt8>, SynthesisError> {
98 let mut x = self.x.to_non_unique_bytes(&mut cs.ns(|| "x to bytes"))?;
99 let mut y = self.y.to_non_unique_bytes(&mut cs.ns(|| "y to bytes"))?;
100 let mut x_twist = self
101 .x_twist
102 .to_non_unique_bytes(&mut cs.ns(|| "x_twist to bytes"))?;
103 let mut y_twist = self
104 .y_twist
105 .to_non_unique_bytes(&mut cs.ns(|| "y_twist to bytes"))?;
106
107 x.append(&mut y);
108 x.append(&mut x_twist);
109 x.append(&mut y_twist);
110 Ok(x)
111 }
112}
113
114type Fp3G<P> = Fp3Gadget<<P as MNT6Parameters>::Fp3Params, <P as MNT6Parameters>::Fp>;
115#[derive(Derivative)]
116#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
117pub struct G2PreparedGadget<P: MNT6Parameters> {
118 pub x: Fp3Gadget<P::Fp3Params, P::Fp>,
119 pub y: Fp3Gadget<P::Fp3Params, P::Fp>,
120 pub x_over_twist: Fp3Gadget<P::Fp3Params, P::Fp>,
121 pub y_over_twist: Fp3Gadget<P::Fp3Params, P::Fp>,
122 pub double_coefficients: Vec<AteDoubleCoefficientsGadget<P>>,
123 pub addition_coefficients: Vec<AteAdditionCoefficientsGadget<P>>,
124}
125
126impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G2PreparedGadget<P> {
127 #[inline]
128 fn to_bytes<CS: ConstraintSystem<P::Fp>>(
129 &self,
130 mut cs: CS,
131 ) -> Result<Vec<UInt8>, SynthesisError> {
132 let mut x = self.x.to_bytes(&mut cs.ns(|| "x to bytes"))?;
133 let mut y = self.y.to_bytes(&mut cs.ns(|| "y to bytes"))?;
134 let mut x_over_twist = self
135 .x_over_twist
136 .to_bytes(&mut cs.ns(|| "x_over_twist to bytes"))?;
137 let mut y_over_twist = self
138 .y_over_twist
139 .to_bytes(&mut cs.ns(|| "y_over_twist to bytes"))?;
140
141 x.append(&mut y);
142 x.append(&mut x_over_twist);
143 x.append(&mut y_over_twist);
144
145 for (i, coeff) in self.double_coefficients.iter().enumerate() {
146 x.extend_from_slice(&coeff.to_bytes(cs.ns(|| format!("double_coefficients {}", i)))?);
147 }
148 for (i, coeff) in self.addition_coefficients.iter().enumerate() {
149 x.extend_from_slice(&coeff.to_bytes(cs.ns(|| format!("addition_coefficients {}", i)))?);
150 }
151 Ok(x)
152 }
153
154 fn to_non_unique_bytes<CS: ConstraintSystem<P::Fp>>(
155 &self,
156 mut cs: CS,
157 ) -> Result<Vec<UInt8>, SynthesisError> {
158 let mut x = self.x.to_non_unique_bytes(&mut cs.ns(|| "x to bytes"))?;
159 let mut y = self.y.to_non_unique_bytes(&mut cs.ns(|| "y to bytes"))?;
160 let mut x_over_twist = self
161 .x_over_twist
162 .to_non_unique_bytes(&mut cs.ns(|| "x_over_twist to bytes"))?;
163 let mut y_over_twist = self
164 .y_over_twist
165 .to_non_unique_bytes(&mut cs.ns(|| "y_over_twist to bytes"))?;
166
167 x.append(&mut y);
168 x.append(&mut x_over_twist);
169 x.append(&mut y_over_twist);
170
171 for (i, coeff) in self.double_coefficients.iter().enumerate() {
172 x.extend_from_slice(
173 &coeff.to_non_unique_bytes(cs.ns(|| format!("double_coefficients {}", i)))?,
174 );
175 }
176 for (i, coeff) in self.addition_coefficients.iter().enumerate() {
177 x.extend_from_slice(
178 &coeff.to_non_unique_bytes(cs.ns(|| format!("addition_coefficients {}", i)))?,
179 );
180 }
181 Ok(x)
182 }
183}
184
185impl<P: MNT6Parameters> G2PreparedGadget<P> {
186 pub fn get_value(&self) -> Option<G2Prepared<P>> {
187 match (
188 self.x.get_value(),
189 self.y.get_value(),
190 self.x_over_twist.get_value(),
191 self.y_over_twist.get_value(),
192 self.double_coefficients
193 .iter()
194 .map(|coeff| coeff.get_value())
195 .collect::<Option<Vec<AteDoubleCoefficients<P>>>>(),
196 self.addition_coefficients
197 .iter()
198 .map(|coeff| coeff.get_value())
199 .collect::<Option<Vec<AteAdditionCoefficients<P>>>>(),
200 ) {
201 (
202 Some(x),
203 Some(y),
204 Some(x_over_twist),
205 Some(y_over_twist),
206 Some(double_coefficients),
207 Some(addition_coefficients),
208 ) => Some(G2Prepared {
209 x,
210 y,
211 x_over_twist,
212 y_over_twist,
213 double_coefficients,
214 addition_coefficients,
215 }),
216 _ => None,
217 }
218 }
219
220 pub fn from_affine<CS: ConstraintSystem<P::Fp>>(
221 mut cs: CS,
222 q: &G2Gadget<P>,
223 ) -> Result<Self, SynthesisError> {
224 let twist_inv = P::TWIST.inverse().unwrap();
225
226 let mut g2p = G2PreparedGadget {
227 x: q.x.clone(),
228 y: q.y.clone(),
229 x_over_twist: q.x.mul_by_constant(cs.ns(|| "x over twist"), &twist_inv)?,
230 y_over_twist: q.y.mul_by_constant(cs.ns(|| "y over twist"), &twist_inv)?,
231 double_coefficients: vec![],
232 addition_coefficients: vec![],
233 };
234
235 let fp2_one = Fp3G::<P>::one(cs.ns(|| "one"))?;
236 let mut r = G2ProjectiveExtendedGadget {
237 x: q.x.clone(),
238 y: q.y.clone(),
239 z: fp2_one.clone(),
240 t: fp2_one,
241 };
242
243 for (idx, value) in P::ATE_LOOP_COUNT.iter().rev().enumerate() {
244 let mut tmp = *value;
245 let skip_extraneous_bits = 64 - value.leading_zeros();
246 let mut v = Vec::with_capacity(16);
247 for i in 0..64 {
248 if idx == 0 && (i == 0 || i >= skip_extraneous_bits) {
249 continue;
250 }
251 v.push(tmp & 1 == 1);
252 tmp >>= 1;
253 }
254
255 let mut cs = cs.ns(|| format!("ate loop iteration {}", idx));
256
257 for (j, bit) in v.iter().rev().enumerate() {
258 let (r2, coeff) = PairingGadget::<P>::doubling_step_for_flipped_miller_loop(
259 cs.ns(|| format!("doubling step {}", j)),
260 &r,
261 )?;
262 g2p.double_coefficients.push(coeff);
263 r = r2;
264
265 if *bit {
266 let (r2, coeff) =
267 PairingGadget::<P>::mixed_addition_step_for_flipped_miller_loop(
268 cs.ns(|| format!("mixed addition step {}", j)),
269 &q.x,
270 &q.y,
271 &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(cs.ns(|| "inverse r.z"))?;
283 let rz2_inv = rz_inv.square(cs.ns(|| "rz_inv^2"))?;
284 let rz3_inv = rz_inv.mul(cs.ns(|| "rz_inv * rz_inv^2"), &rz2_inv)?;
285
286 let minus_r_affine_x = r.x.mul(cs.ns(|| "r.x * rz2_inv"), &rz2_inv)?;
287 let minus_r_affine_y =
288 r.y.negate(cs.ns(|| "-r.y"))?
289 .mul(cs.ns(|| "-r.y * rz3_inv"), &rz3_inv)?;
290
291 let add_result = PairingGadget::<P>::mixed_addition_step_for_flipped_miller_loop(
292 cs.ns(|| "mixed_addition step"),
293 &minus_r_affine_x,
294 &minus_r_affine_y,
295 &r,
296 )?;
297 g2p.addition_coefficients.push(add_result.1);
298 }
299
300 Ok(g2p)
301 }
302}
303
304#[derive(Derivative)]
305#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
306pub struct AteDoubleCoefficientsGadget<P: MNT6Parameters> {
307 pub c_h: Fp3Gadget<P::Fp3Params, P::Fp>,
308 pub c_4c: Fp3Gadget<P::Fp3Params, P::Fp>,
309 pub c_j: Fp3Gadget<P::Fp3Params, P::Fp>,
310 pub c_l: Fp3Gadget<P::Fp3Params, P::Fp>,
311}
312
313impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsGadget<P> {
314 #[inline]
315 fn to_bytes<CS: ConstraintSystem<P::Fp>>(
316 &self,
317 mut cs: CS,
318 ) -> Result<Vec<UInt8>, SynthesisError> {
319 let mut c_h = self.c_h.to_bytes(&mut cs.ns(|| "c_h to bytes"))?;
320 let mut c_4c = self.c_4c.to_bytes(&mut cs.ns(|| "c_4c to bytes"))?;
321 let mut c_j = self.c_j.to_bytes(&mut cs.ns(|| "c_j to bytes"))?;
322 let mut c_l = self.c_l.to_bytes(&mut cs.ns(|| "c_l to bytes"))?;
323
324 c_h.append(&mut c_4c);
325 c_h.append(&mut c_j);
326 c_h.append(&mut c_l);
327 Ok(c_h)
328 }
329
330 fn to_non_unique_bytes<CS: ConstraintSystem<P::Fp>>(
331 &self,
332 mut cs: CS,
333 ) -> Result<Vec<UInt8>, SynthesisError> {
334 let mut c_h = self
335 .c_h
336 .to_non_unique_bytes(&mut cs.ns(|| "c_h to bytes"))?;
337 let mut c_4c = self
338 .c_4c
339 .to_non_unique_bytes(&mut cs.ns(|| "c_4c to bytes"))?;
340 let mut c_j = self
341 .c_j
342 .to_non_unique_bytes(&mut cs.ns(|| "c_j to bytes"))?;
343 let mut c_l = self
344 .c_l
345 .to_non_unique_bytes(&mut cs.ns(|| "c_l to bytes"))?;
346
347 c_h.append(&mut c_4c);
348 c_h.append(&mut c_j);
349 c_h.append(&mut c_l);
350 Ok(c_h)
351 }
352}
353
354impl<P: MNT6Parameters> AteDoubleCoefficientsGadget<P> {
355 pub fn get_value(&self) -> Option<AteDoubleCoefficients<P>> {
356 match (
357 self.c_h.get_value(),
358 self.c_4c.get_value(),
359 self.c_j.get_value(),
360 self.c_l.get_value(),
361 ) {
362 (Some(c_h), Some(c_4c), Some(c_j), Some(c_l)) => Some(AteDoubleCoefficients {
363 c_h,
364 c_4c,
365 c_j,
366 c_l,
367 }),
368 _ => None,
369 }
370 }
371}
372
373#[derive(Derivative)]
374#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
375pub struct AteAdditionCoefficientsGadget<P: MNT6Parameters> {
376 pub c_l1: Fp3Gadget<P::Fp3Params, P::Fp>,
377 pub c_rz: Fp3Gadget<P::Fp3Params, P::Fp>,
378}
379
380impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsGadget<P> {
381 #[inline]
382 fn to_bytes<CS: ConstraintSystem<P::Fp>>(
383 &self,
384 mut cs: CS,
385 ) -> Result<Vec<UInt8>, SynthesisError> {
386 let mut c_l1 = self.c_l1.to_bytes(&mut cs.ns(|| "c_l1 to bytes"))?;
387 let mut c_rz = self.c_rz.to_bytes(&mut cs.ns(|| "c_rz to bytes"))?;
388
389 c_l1.append(&mut c_rz);
390 Ok(c_l1)
391 }
392
393 fn to_non_unique_bytes<CS: ConstraintSystem<P::Fp>>(
394 &self,
395 mut cs: CS,
396 ) -> Result<Vec<UInt8>, SynthesisError> {
397 let mut c_l1 = self
398 .c_l1
399 .to_non_unique_bytes(&mut cs.ns(|| "c_l1 to bytes"))?;
400 let mut c_rz = self
401 .c_rz
402 .to_non_unique_bytes(&mut cs.ns(|| "c_rz to bytes"))?;
403
404 c_l1.append(&mut c_rz);
405 Ok(c_l1)
406 }
407}
408
409impl<P: MNT6Parameters> AteAdditionCoefficientsGadget<P> {
410 pub fn get_value(&self) -> Option<AteAdditionCoefficients<P>> {
411 match (self.c_l1.get_value(), self.c_rz.get_value()) {
412 (Some(c_l1), Some(c_rz)) => Some(AteAdditionCoefficients { c_l1, c_rz }),
413 _ => None,
414 }
415 }
416}
417
418pub struct G2ProjectiveExtendedGadget<P: MNT6Parameters> {
419 pub x: Fp3Gadget<P::Fp3Params, P::Fp>,
420 pub y: Fp3Gadget<P::Fp3Params, P::Fp>,
421 pub z: Fp3Gadget<P::Fp3Params, P::Fp>,
422 pub t: Fp3Gadget<P::Fp3Params, P::Fp>,
423}