use algebra::{ curves::mnt4::{ g2::{AteAdditionCoefficients, AteDoubleCoefficients}, G1Prepared, G2Prepared, MNT4Parameters, }, Field, }; use r1cs_core::{ConstraintSystem, SynthesisError}; use crate::{ fields::{fp::FpGadget, fp2::Fp2Gadget, FieldGadget}, groups::curves::short_weierstrass::AffineGadget, pairing::mnt4::PairingGadget, prelude::*, Vec, }; pub type G1Gadget

= AffineGadget<

::G1Parameters,

::Fp, FpGadget<

::Fp>, >; pub type G2Gadget

= AffineGadget<

::G2Parameters,

::Fp, Fp2G

>; #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] pub struct G1PreparedGadget { pub x: FpGadget, pub y: FpGadget, pub x_twist: Fp2Gadget, pub y_twist: Fp2Gadget, } impl G1PreparedGadget

{ pub fn get_value(&self) -> Option> { match ( self.x.get_value(), self.y.get_value(), self.x_twist.get_value(), self.y_twist.get_value(), ) { (Some(x), Some(y), Some(x_twist), Some(y_twist)) => Some(G1Prepared { x, y, x_twist, y_twist, }), _ => None, } } pub fn from_affine>( mut cs: CS, q: &G1Gadget

, ) -> Result { let x_twist = Fp2Gadget::new( q.x.mul_by_constant(cs.ns(|| "g1.x * twist.c0"), &P::TWIST.c0)?, q.x.mul_by_constant(cs.ns(|| "g1.x * twist.c1"), &P::TWIST.c1)?, ); let y_twist = Fp2Gadget::new( q.y.mul_by_constant(cs.ns(|| "g1.y * twist.c0"), &P::TWIST.c0)?, q.y.mul_by_constant(cs.ns(|| "g1.y * twist.c1"), &P::TWIST.c1)?, ); Ok(G1PreparedGadget { x: q.x.clone(), y: q.y.clone(), x_twist, y_twist, }) } } impl ToBytesGadget for G1PreparedGadget

{ #[inline] fn to_bytes>( &self, mut cs: CS, ) -> Result, SynthesisError> { let mut x = self.x.to_bytes(&mut cs.ns(|| "x to bytes"))?; let mut y = self.y.to_bytes(&mut cs.ns(|| "y to bytes"))?; let mut x_twist = self.x_twist.to_bytes(&mut cs.ns(|| "x_twist to bytes"))?; let mut y_twist = self.y_twist.to_bytes(&mut cs.ns(|| "y_twist to bytes"))?; x.append(&mut y); x.append(&mut x_twist); x.append(&mut y_twist); Ok(x) } fn to_non_unique_bytes>( &self, mut cs: CS, ) -> Result, SynthesisError> { let mut x = self.x.to_non_unique_bytes(&mut cs.ns(|| "x to bytes"))?; let mut y = self.y.to_non_unique_bytes(&mut cs.ns(|| "y to bytes"))?; let mut x_twist = self .x_twist .to_non_unique_bytes(&mut cs.ns(|| "x_twist to bytes"))?; let mut y_twist = self .y_twist .to_non_unique_bytes(&mut cs.ns(|| "y_twist to bytes"))?; x.append(&mut y); x.append(&mut x_twist); x.append(&mut y_twist); Ok(x) } } type Fp2G

= Fp2Gadget<

::Fp2Params,

::Fp>; #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] pub struct G2PreparedGadget { pub x: Fp2Gadget, pub y: Fp2Gadget, pub x_over_twist: Fp2Gadget, pub y_over_twist: Fp2Gadget, pub double_coefficients: Vec>, pub addition_coefficients: Vec>, } impl ToBytesGadget for G2PreparedGadget

{ #[inline] fn to_bytes>( &self, mut cs: CS, ) -> Result, SynthesisError> { let mut x = self.x.to_bytes(&mut cs.ns(|| "x to bytes"))?; let mut y = self.y.to_bytes(&mut cs.ns(|| "y to bytes"))?; let mut x_over_twist = self .x_over_twist .to_bytes(&mut cs.ns(|| "x_over_twist to bytes"))?; let mut y_over_twist = self .y_over_twist .to_bytes(&mut cs.ns(|| "y_over_twist to bytes"))?; x.append(&mut y); x.append(&mut x_over_twist); x.append(&mut y_over_twist); for (i, coeff) in self.double_coefficients.iter().enumerate() { x.extend_from_slice(&coeff.to_bytes(cs.ns(|| format!("double_coefficients {}", i)))?); } for (i, coeff) in self.addition_coefficients.iter().enumerate() { x.extend_from_slice(&coeff.to_bytes(cs.ns(|| format!("addition_coefficients {}", i)))?); } Ok(x) } fn to_non_unique_bytes>( &self, mut cs: CS, ) -> Result, SynthesisError> { let mut x = self.x.to_non_unique_bytes(&mut cs.ns(|| "x to bytes"))?; let mut y = self.y.to_non_unique_bytes(&mut cs.ns(|| "y to bytes"))?; let mut x_over_twist = self .x_over_twist .to_non_unique_bytes(&mut cs.ns(|| "x_over_twist to bytes"))?; let mut y_over_twist = self .y_over_twist .to_non_unique_bytes(&mut cs.ns(|| "y_over_twist to bytes"))?; x.append(&mut y); x.append(&mut x_over_twist); x.append(&mut y_over_twist); for (i, coeff) in self.double_coefficients.iter().enumerate() { x.extend_from_slice( &coeff.to_non_unique_bytes(cs.ns(|| format!("double_coefficients {}", i)))?, ); } for (i, coeff) in self.addition_coefficients.iter().enumerate() { x.extend_from_slice( &coeff.to_non_unique_bytes(cs.ns(|| format!("addition_coefficients {}", i)))?, ); } Ok(x) } } impl G2PreparedGadget

{ pub fn get_value(&self) -> Option> { match ( self.x.get_value(), self.y.get_value(), self.x_over_twist.get_value(), self.y_over_twist.get_value(), self.double_coefficients .iter() .map(|coeff| coeff.get_value()) .collect::>>>(), self.addition_coefficients .iter() .map(|coeff| coeff.get_value()) .collect::>>>(), ) { ( Some(x), Some(y), Some(x_over_twist), Some(y_over_twist), Some(double_coefficients), Some(addition_coefficients), ) => Some(G2Prepared { x, y, x_over_twist, y_over_twist, double_coefficients, addition_coefficients, }), _ => None, } } pub fn from_affine>( mut cs: CS, q: &G2Gadget

, ) -> Result { let twist_inv = P::TWIST.inverse().unwrap(); let mut g2p = G2PreparedGadget { x: q.x.clone(), y: q.y.clone(), x_over_twist: q.x.mul_by_constant(cs.ns(|| "x over twist"), &twist_inv)?, y_over_twist: q.y.mul_by_constant(cs.ns(|| "y over twist"), &twist_inv)?, double_coefficients: vec![], addition_coefficients: vec![], }; let fp2_one = Fp2G::

::one(cs.ns(|| "one"))?; let mut r = G2ProjectiveExtendedGadget { x: q.x.clone(), y: q.y.clone(), z: fp2_one.clone(), t: fp2_one, }; for (idx, value) in P::ATE_LOOP_COUNT.iter().rev().enumerate() { let mut tmp = *value; let skip_extraneous_bits = 64 - value.leading_zeros(); let mut v = Vec::with_capacity(16); for i in 0..64 { if idx == 0 && (i == 0 || i >= skip_extraneous_bits) { continue; } v.push(tmp & 1 == 1); tmp >>= 1; } let mut cs = cs.ns(|| format!("ate loop iteration {}", idx)); for (j, bit) in v.iter().rev().enumerate() { let (r2, coeff) = PairingGadget::

::doubling_step_for_flipped_miller_loop( cs.ns(|| format!("doubling step {}", j)), &r, )?; g2p.double_coefficients.push(coeff); r = r2; if *bit { let (r2, coeff) = PairingGadget::

::mixed_addition_step_for_flipped_miller_loop( cs.ns(|| format!("mixed addition step {}", j)), &q.x, &q.y, &r, )?; g2p.addition_coefficients.push(coeff); r = r2; } tmp >>= 1; } } if P::ATE_IS_LOOP_COUNT_NEG { let rz_inv = r.z.inverse(cs.ns(|| "inverse r.z"))?; let rz2_inv = rz_inv.square(cs.ns(|| "rz_inv^2"))?; let rz3_inv = rz_inv.mul(cs.ns(|| "rz_inv * rz_inv^2"), &rz2_inv)?; let minus_r_affine_x = r.x.mul(cs.ns(|| "r.x * rz2_inv"), &rz2_inv)?; let minus_r_affine_y = r.y.negate(cs.ns(|| "-r.y"))? .mul(cs.ns(|| "-r.y * rz3_inv"), &rz3_inv)?; let add_result = PairingGadget::

::mixed_addition_step_for_flipped_miller_loop( cs.ns(|| "mixed_addition step"), &minus_r_affine_x, &minus_r_affine_y, &r, )?; g2p.addition_coefficients.push(add_result.1); } Ok(g2p) } } #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] pub struct AteDoubleCoefficientsGadget { pub c_h: Fp2Gadget, pub c_4c: Fp2Gadget, pub c_j: Fp2Gadget, pub c_l: Fp2Gadget, } impl ToBytesGadget for AteDoubleCoefficientsGadget

{ #[inline] fn to_bytes>( &self, mut cs: CS, ) -> Result, SynthesisError> { let mut c_h = self.c_h.to_bytes(&mut cs.ns(|| "c_h to bytes"))?; let mut c_4c = self.c_4c.to_bytes(&mut cs.ns(|| "c_4c to bytes"))?; let mut c_j = self.c_j.to_bytes(&mut cs.ns(|| "c_j to bytes"))?; let mut c_l = self.c_l.to_bytes(&mut cs.ns(|| "c_l to bytes"))?; c_h.append(&mut c_4c); c_h.append(&mut c_j); c_h.append(&mut c_l); Ok(c_h) } fn to_non_unique_bytes>( &self, mut cs: CS, ) -> Result, SynthesisError> { let mut c_h = self .c_h .to_non_unique_bytes(&mut cs.ns(|| "c_h to bytes"))?; let mut c_4c = self .c_4c .to_non_unique_bytes(&mut cs.ns(|| "c_4c to bytes"))?; let mut c_j = self .c_j .to_non_unique_bytes(&mut cs.ns(|| "c_j to bytes"))?; let mut c_l = self .c_l .to_non_unique_bytes(&mut cs.ns(|| "c_l to bytes"))?; c_h.append(&mut c_4c); c_h.append(&mut c_j); c_h.append(&mut c_l); Ok(c_h) } } impl AteDoubleCoefficientsGadget

{ pub fn get_value(&self) -> Option> { match ( self.c_h.get_value(), self.c_4c.get_value(), self.c_j.get_value(), self.c_l.get_value(), ) { (Some(c_h), Some(c_4c), Some(c_j), Some(c_l)) => Some(AteDoubleCoefficients { c_h, c_4c, c_j, c_l, }), _ => None, } } } #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] pub struct AteAdditionCoefficientsGadget { pub c_l1: Fp2Gadget, pub c_rz: Fp2Gadget, } impl ToBytesGadget for AteAdditionCoefficientsGadget

{ #[inline] fn to_bytes>( &self, mut cs: CS, ) -> Result, SynthesisError> { let mut c_l1 = self.c_l1.to_bytes(&mut cs.ns(|| "c_l1 to bytes"))?; let mut c_rz = self.c_rz.to_bytes(&mut cs.ns(|| "c_rz to bytes"))?; c_l1.append(&mut c_rz); Ok(c_l1) } fn to_non_unique_bytes>( &self, mut cs: CS, ) -> Result, SynthesisError> { let mut c_l1 = self .c_l1 .to_non_unique_bytes(&mut cs.ns(|| "c_l1 to bytes"))?; let mut c_rz = self .c_rz .to_non_unique_bytes(&mut cs.ns(|| "c_rz to bytes"))?; c_l1.append(&mut c_rz); Ok(c_l1) } } impl AteAdditionCoefficientsGadget

{ pub fn get_value(&self) -> Option> { match (self.c_l1.get_value(), self.c_rz.get_value()) { (Some(c_l1), Some(c_rz)) => Some(AteAdditionCoefficients { c_l1, c_rz }), _ => None, } } } pub struct G2ProjectiveExtendedGadget { pub x: Fp2Gadget, pub y: Fp2Gadget, pub z: Fp2Gadget, pub t: Fp2Gadget, }