use algebra::{ curves::mnt6::{ g2::{AteAdditionCoefficients, AteDoubleCoefficients}, G1Prepared, G2Prepared, MNT6Parameters, }, Field, }; use core::borrow::Borrow; use r1cs_core::{ConstraintSystem, SynthesisError}; use crate::{ fields::{fp::FpGadget, fp3::Fp3Gadget, FieldGadget}, groups::curves::short_weierstrass::AffineGadget, pairing::mnt6::PairingGadget, prelude::*, Vec, }; pub type G1Gadget

= AffineGadget<

::G1Parameters,

::Fp, FpGadget<

::Fp>, >; pub type G2Gadget

= AffineGadget<

::G2Parameters,

::Fp, Fp3G

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

{ fn alloc_constant>( mut cs: CS, t: T, ) -> Result where T: Borrow>, { let obj = t.borrow(); let x_gadget = FpGadget::::alloc_constant(&mut cs.ns(|| "x"), &obj.x)?; let y_gadget = FpGadget::::alloc_constant(&mut cs.ns(|| "y"), &obj.y)?; let x_twist_gadget = Fp3Gadget::::alloc_constant( &mut cs.ns(|| "x_twist"), &obj.x_twist, )?; let y_twist_gadget = Fp3Gadget::::alloc_constant( &mut cs.ns(|| "y_twist"), &obj.y_twist, )?; Ok(Self { x: x_gadget, y: y_gadget, x_twist: x_twist_gadget, y_twist: y_twist_gadget, }) } fn alloc>(_cs: CS, _f: F) -> Result where F: FnOnce() -> Result, T: Borrow>, { todo!() } fn alloc_input>( _cs: CS, _f: F, ) -> Result where F: FnOnce() -> Result, T: Borrow>, { todo!() } } 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 = Fp3Gadget::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)?, q.x.mul_by_constant(cs.ns(|| "g1.x * twist.c2"), &P::TWIST.c2)?, ); let y_twist = Fp3Gadget::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)?, q.y.mul_by_constant(cs.ns(|| "g1.y * twist.c2"), &P::TWIST.c2)?, ); 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 Fp3G

= Fp3Gadget<

::Fp3Params,

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

{ fn alloc_constant>( mut cs: CS, t: T, ) -> Result where T: Borrow>, { let obj = t.borrow(); let x_gadget = Fp3Gadget::::alloc_constant(&mut cs.ns(|| "x"), &obj.x)?; let y_gadget = Fp3Gadget::::alloc_constant(&mut cs.ns(|| "y"), &obj.y)?; let x_over_twist_gadget = Fp3Gadget::::alloc_constant( &mut cs.ns(|| "x_over_twist"), &obj.x_over_twist, )?; let y_over_twist_gadget = Fp3Gadget::::alloc_constant( &mut cs.ns(|| "y_over_twist"), &obj.y_over_twist, )?; let mut double_coefficients_gadget = Vec::>::new(); for (i, double_coefficient) in obj.double_coefficients.iter().enumerate() { double_coefficients_gadget.push(AteDoubleCoefficientsGadget::

::alloc_constant( &mut cs.ns(|| format!("double_coefficient#{}", i)), double_coefficient, )?); } let mut addition_coefficients_gadget = Vec::>::new(); for (i, addition_coefficient) in obj.addition_coefficients.iter().enumerate() { addition_coefficients_gadget.push(AteAdditionCoefficientsGadget::

::alloc_constant( &mut cs.ns(|| format!("addition_coefficient#{}", i)), addition_coefficient, )?); } Ok(Self { x: x_gadget, y: y_gadget, x_over_twist: x_over_twist_gadget, y_over_twist: y_over_twist_gadget, double_coefficients: double_coefficients_gadget, addition_coefficients: addition_coefficients_gadget, }) } fn alloc>(_cs: CS, _f: F) -> Result where F: FnOnce() -> Result, T: Borrow>, { todo!() } fn alloc_input>( _cs: CS, _f: F, ) -> Result where F: FnOnce() -> Result, T: Borrow>, { todo!() } } 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 = Fp3G::

::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: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))] pub struct AteDoubleCoefficientsGadget { pub c_h: Fp3Gadget, pub c_4c: Fp3Gadget, pub c_j: Fp3Gadget, pub c_l: Fp3Gadget, } impl AllocGadget, P::Fp> for AteDoubleCoefficientsGadget

{ fn alloc_constant>( mut cs: CS, t: T, ) -> Result where T: Borrow>, { let obj = t.borrow(); let c_h_gadget = Fp3Gadget::::alloc_constant(&mut cs.ns(|| "c_h"), &obj.c_h)?; let c_4c_gadget = Fp3Gadget::::alloc_constant(&mut cs.ns(|| "c_4c"), &obj.c_4c)?; let c_j_gadget = Fp3Gadget::::alloc_constant(&mut cs.ns(|| "c_j"), &obj.c_j)?; let c_l_gadget = Fp3Gadget::::alloc_constant(&mut cs.ns(|| "c_l"), &obj.c_l)?; Ok(Self { c_h: c_h_gadget, c_4c: c_4c_gadget, c_j: c_j_gadget, c_l: c_l_gadget, }) } fn alloc>(_cs: CS, _f: F) -> Result where F: FnOnce() -> Result, T: Borrow>, { todo!() } fn alloc_input>( _cs: CS, _f: F, ) -> Result where F: FnOnce() -> Result, T: Borrow>, { todo!() } } 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: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))] pub struct AteAdditionCoefficientsGadget { pub c_l1: Fp3Gadget, pub c_rz: Fp3Gadget, } impl AllocGadget, P::Fp> for AteAdditionCoefficientsGadget

{ fn alloc_constant>( mut cs: CS, t: T, ) -> Result where T: Borrow>, { let t = t.borrow(); let c_l1 = Fp3Gadget::alloc_constant(&mut cs.ns(|| "c_l1"), &t.c_l1)?; let c_rz = Fp3Gadget::alloc_constant(&mut cs.ns(|| "c_rz"), &t.c_rz)?; Ok(Self { c_l1, c_rz }) } fn alloc>(_cs: CS, _f: F) -> Result where F: FnOnce() -> Result, T: Borrow>, { todo!() } fn alloc_input>( _cs: CS, _f: F, ) -> Result where F: FnOnce() -> Result, T: Borrow>, { todo!() } } 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: Fp3Gadget, pub y: Fp3Gadget, pub z: Fp3Gadget, pub t: Fp3Gadget, }