arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
Use 2-NAF for representing ATE_LOOP_COUNT in MNT Miller loop (#96)

* 2-NAF for MNT pairings

* Apply suggestions from code review

* Apply suggestions from code review

* fix

* no std

* patch

* ci

Co-authored-by: Weikeng Chen <w.k@berkeley.edu>
Co-authored-by: onewayfunc <onewayfunc@gmail.com>
mmagician marcin.gorny.94@protonmail.com
Sat, 03 Sep 2022 09:15:45 +0200
commit

6512e48540cf98d4bb9e1a4b2badd077867f510a

parent

db6a3d6687b84935b92429efb902fb11c4fdad9f

M .github/workflows/ci.yml → .github/workflows/ci.yml

@@ -187,6 +187,7 @@ echo "ark-ec = { git = 'https://github.com/arkworks-rs/algebra' }"

echo "ark-ff = { git = 'https://github.com/arkworks-rs/algebra' }" echo "ark-poly = { git = 'https://github.com/arkworks-rs/algebra' }" echo "ark-serialize = { git = 'https://github.com/arkworks-rs/algebra' }" + echo "ark-algebra-bench-templates = { git = 'https://github.com/arkworks-rs/algebra' }" echo "ark-algebra-test-templates = { git = 'https://github.com/arkworks-rs/algebra' }" echo "ark-r1cs-std = { path = 'r1cs-std' }" } >> Cargo.toml
M Cargo.toml → Cargo.toml

@@ -77,6 +77,7 @@ ark-std = { git = "https://github.com/arkworks-rs/std" }

ark-ec = { git = "https://github.com/arkworks-rs/algebra" } ark-ff = { git = "https://github.com/arkworks-rs/algebra" } ark-poly = { git = "https://github.com/arkworks-rs/algebra" } +ark-algebra-bench-templates = { git = "https://github.com/arkworks-rs/algebra" } ark-test-curves = { git = "https://github.com/arkworks-rs/algebra" } ark-bls12-381 = { git = "https://github.com/arkworks-rs/curves" } ark-bls12-377 = { git = "https://github.com/arkworks-rs/curves" }
M src/groups/curves/short_weierstrass/bls12/mod.rs → src/groups/curves/short_weierstrass/bls12/mod.rs

@@ -43,7 +43,7 @@ let x = self.0.x.value()?;

let y = self.0.y.value()?; let infinity = self.0.infinity.value()?; let g = infinity - .then_some(GroupAffine::zero()) + .then_some(GroupAffine::identity()) .unwrap_or(GroupAffine::new(x, y)) .into(); Ok(g)
M src/groups/curves/short_weierstrass/mnt4/mod.rs → src/groups/curves/short_weierstrass/mnt4/mod.rs

@@ -291,33 +291,32 @@ z: Fp2G::<P>::one(),

t: Fp2G::<P>::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; - } + for bit in P::ATE_LOOP_COUNT.iter().skip(1) { + let (r2, coeff) = PairingVar::<P>::doubling_step_for_flipped_miller_loop(&r)?; + g2p.double_coefficients.push(coeff); + r = r2; - for bit in v.iter().rev() { - let (r2, coeff) = PairingVar::<P>::doubling_step_for_flipped_miller_loop(&r)?; - g2p.double_coefficients.push(coeff); - r = r2; - - if *bit { - let (r2, coeff) = PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop( - &q.x, &q.y, &r, - )?; - g2p.addition_coefficients.push(coeff); - r = r2; - } - - tmp >>= 1; + let add_coeff; + let r_temp; + match bit { + 1 => { + (r_temp, add_coeff) = + PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop( + &q.x, &q.y, &r, + )?; + }, + -1 => { + (r_temp, add_coeff) = + PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop( + &q.x, + &q.y.negate()?, + &r, + )?; + }, + _ => continue, } + g2p.addition_coefficients.push(add_coeff); + r = r_temp; } if P::ATE_IS_LOOP_COUNT_NEG {
M src/groups/curves/short_weierstrass/mnt6/mod.rs → src/groups/curves/short_weierstrass/mnt6/mod.rs

@@ -291,33 +291,32 @@ z: Fp3G::<P>::one(),

t: Fp3G::<P>::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; - } + for bit in P::ATE_LOOP_COUNT.iter().skip(1) { + let (r2, coeff) = PairingVar::<P>::doubling_step_for_flipped_miller_loop(&r)?; + g2p.double_coefficients.push(coeff); + r = r2; - for bit in v.iter().rev() { - let (r2, coeff) = PairingVar::<P>::doubling_step_for_flipped_miller_loop(&r)?; - g2p.double_coefficients.push(coeff); - r = r2; - - if *bit { - let (r2, coeff) = PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop( - &q.x, &q.y, &r, - )?; - g2p.addition_coefficients.push(coeff); - r = r2; - } - - tmp >>= 1; + let add_coeff; + let r_temp; + match bit { + 1 => { + (r_temp, add_coeff) = + PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop( + &q.x, &q.y, &r, + )?; + }, + -1 => { + (r_temp, add_coeff) = + PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop( + &q.x, + &q.y.negate()?, + &r, + )?; + }, + _ => continue, } + g2p.addition_coefficients.push(add_coeff); + r = r_temp; } if P::ATE_IS_LOOP_COUNT_NEG {
M src/groups/curves/short_weierstrass/mod.rs → src/groups/curves/short_weierstrass/mod.rs

@@ -2,7 +2,7 @@ use ark_ec::{

short_weierstrass::{ Affine as SWAffine, Projective as SWProjective, SWCurveConfig as SWModelParameters, }, - AffineCurve, ProjectiveCurve, + AffineRepr, CurveGroup, }; use ark_ff::{BigInteger, BitIteratorBE, Field, One, PrimeField, Zero}; use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError};

@@ -94,7 +94,7 @@ /// Returns the value assigned to `self` in the underlying

/// constraint system. pub fn value(&self) -> Result<SWAffine<P>, SynthesisError> { Ok(match self.infinity.value()? { - true => SWAffine::zero(), + true => SWAffine::identity(), false => SWAffine::new(self.x.value()?, self.y.value()?), }) }

@@ -137,7 +137,7 @@ let (x, y, z) = (self.x.value()?, self.y.value()?, self.z.value()?);

let result = if let Some(z_inv) = z.inverse() { SWAffine::new(x * &z_inv, y * &z_inv) } else { - SWAffine::zero() + SWAffine::identity() }; Ok(result.into()) }

@@ -209,7 +209,7 @@

let (x, y, z) = match f() { Ok(ge) => { let ge = ge.into_affine(); - if ge.is_zero() { + if ge.is_identity() { ( Ok(P::BaseField::zero()), Ok(P::BaseField::one()),

@@ -782,7 +782,11 @@ cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,

f: impl FnOnce() -> Result<T, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError> { - Self::new_variable(cs, || f().map(|b| b.borrow().into_projective()), mode) + Self::new_variable( + cs, + || f().map(|b| SWProjective::from((*b.borrow()).clone())), + mode, + ) } }
M src/groups/curves/short_weierstrass/non_zero_affine.rs → src/groups/curves/short_weierstrass/non_zero_affine.rs

@@ -1,4 +1,6 @@

use super::*; +use ark_ec::Group; +use ark_std::ops::Add; /// An affine representation of a prime order curve point that is guaranteed /// to *not* be the point at infinity.

@@ -43,8 +45,7 @@ /// Performs an addition without checking that other != ±self.

#[tracing::instrument(target = "r1cs", skip(self, other))] pub fn add_unchecked(&self, other: &Self) -> Result<Self, SynthesisError> { if [self, other].is_constant() { - let result = - (self.value()?.into_projective() + other.value()?.into_projective()).into_affine(); + let result = self.value()?.add(other.value()?).into_affine(); Ok(Self::new(F::constant(result.x), F::constant(result.y))) } else { let (x1, y1) = (&self.x, &self.y);

@@ -70,9 +71,11 @@ /// the output is guaranteed to not be the point at infinity.

#[tracing::instrument(target = "r1cs", skip(self))] pub fn double(&self) -> Result<Self, SynthesisError> { if [self].is_constant() { - let result = self.value()?.into_projective().double().into_affine(); + let result = SWProjective::<P>::from(self.value()?) + .double() + .into_affine(); // Panic if the result is zero. - assert!(!result.is_zero()); + assert!(!result.is_identity()); Ok(Self::new(F::constant(result.x), F::constant(result.y))) } else { let (x1, y1) = (&self.x, &self.y);

@@ -236,7 +239,7 @@ CurveVar,

}, R1CSVar, }; - use ark_ec::{models::short_weierstrass::SWCurveConfig, ProjectiveCurve}; + use ark_ec::{models::short_weierstrass::SWCurveConfig, CurveGroup}; use ark_relations::r1cs::ConstraintSystem; use ark_std::{vec::Vec, One}; use ark_test_curves::bls12_381::{g1::Parameters as G1Parameters, Fq};
M src/groups/curves/twisted_edwards/mod.rs → src/groups/curves/twisted_edwards/mod.rs

@@ -3,10 +3,9 @@ twisted_edwards::{

Affine as TEAffine, MontCurveConfig as MontgomeryModelParameter, Projective as TEProjective, TECurveConfig as TEModelParameters, }, - AffineCurve, ProjectiveCurve, + AffineRepr, CurveGroup, Group, }; use ark_ff::{BigInteger, BitIteratorBE, Field, One, PrimeField, Zero}; - use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError}; use crate::{prelude::*, ToConstraintFieldGadget, Vec};

@@ -85,7 +84,7 @@ pub fn from_edwards_to_coords(

p: &TEAffine<P>, ) -> Result<(P::BaseField, P::BaseField), SynthesisError> { let montgomery_point: GroupAffine<P> = if p.y == P::BaseField::one() { - GroupAffine::zero() + GroupAffine::identity() } else if p.x == P::BaseField::zero() { GroupAffine::new(P::BaseField::zero(), P::BaseField::zero()) } else {

@@ -543,7 +542,7 @@ for (bits, multiples) in bits.chunks(2).zip(multiples.chunks(2)) {

if bits.len() == 2 { let mut table = [multiples[0], multiples[1], multiples[0] + multiples[1]]; - TEProjective::batch_normalization(&mut table); + TEProjective::normalize_batch(&mut table); let x_s = [zero.x, table[0].x, table[1].x, table[2].x]; let y_s = [zero.y, table[0].y, table[1].y, table[2].y];

@@ -675,7 +674,11 @@ cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,

f: impl FnOnce() -> Result<Point, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError> { - Self::new_variable(cs, || f().map(|b| b.borrow().into_projective()), mode) + Self::new_variable( + cs, + || f().map(|b| TEProjective::<P>::from((*b.borrow()).clone())), + mode, + ) } }
M src/groups/mod.rs → src/groups/mod.rs

@@ -1,9 +1,9 @@

use crate::prelude::*; -use ark_ec::ProjectiveCurve; use ark_ff::Field; use ark_relations::r1cs::{Namespace, SynthesisError}; use core::ops::{Add, AddAssign, Sub, SubAssign}; +use ark_ec::CurveGroup; use core::{borrow::Borrow, fmt::Debug}; /// This module contains implementations of arithmetic for various curve models.

@@ -25,7 +25,7 @@ }

/// A variable that represents a curve point for /// the curve `C`. -pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>: +pub trait CurveVar<C: CurveGroup, ConstraintF: Field>: 'static + Sized + Clone
M src/pairing/mnt4/mod.rs → src/pairing/mnt4/mod.rs

@@ -10,7 +10,6 @@ G2ProjectiveExtendedVar, G2Var,

}, }; use ark_ec::mnt4::{MNT4Parameters, MNT4}; -use ark_ff::BitIteratorBE; use core::marker::PhantomData;

@@ -105,10 +104,8 @@ let mut add_idx: usize = 0;

// code below gets executed for all bits (EXCEPT the MSB itself) of // mnt6_param_p (skipping leading zeros) in MSB to LSB order - for (dbl_idx, bit) in BitIteratorBE::without_leading_zeros(P::ATE_LOOP_COUNT) - .skip(1) - .enumerate() - { + let y_over_twist_neg = &q.y_over_twist.negate()?; + for (dbl_idx, bit) in P::ATE_LOOP_COUNT.iter().skip(1).enumerate() { let dc = &q.double_coefficients[dbl_idx]; let g_rr_at_p = Fp4G::<P>::new(

@@ -118,16 +115,29 @@ );

f = f.square()? * &g_rr_at_p; - if bit { + let g_rq_at_p; + // Compute l_{R,Q}(P) if bit == 1, and l_{R,-Q}(P) if bit == -1 + if *bit == 1 { let ac = &q.addition_coefficients[add_idx]; add_idx += 1; - let g_rq_at_p = Fp4G::<P>::new( + g_rq_at_p = Fp4G::<P>::new( &ac.c_rz * &p.y_twist, (&q.y_over_twist * &ac.c_rz + &l1_coeff * &ac.c_l1).negate()?, ); - f *= &g_rq_at_p; + } else if *bit == -1 { + let ac = &q.addition_coefficients[add_idx]; + add_idx += 1; + + g_rq_at_p = Fp4G::<P>::new( + &ac.c_rz * &p.y_twist, + (y_over_twist_neg * &ac.c_rz + &l1_coeff * &ac.c_l1).negate()?, + ); + } else { + continue; } + + f *= &g_rq_at_p; } if P::ATE_IS_LOOP_COUNT_NEG {
M src/pairing/mnt6/mod.rs → src/pairing/mnt6/mod.rs

@@ -10,7 +10,6 @@ G2ProjectiveExtendedVar, G2Var,

}, }; use ark_ec::mnt6::{MNT6Parameters, MNT6}; -use ark_ff::fields::BitIteratorBE; use core::marker::PhantomData; /// Specifies the constraints for computing a pairing in a MNT6 bilinear group.

@@ -100,29 +99,40 @@ let mut add_idx: usize = 0;

// code below gets executed for all bits (EXCEPT the MSB itself) of // mnt6_param_p (skipping leading zeros) in MSB to LSB order - for (dbl_idx, bit) in BitIteratorBE::without_leading_zeros(P::ATE_LOOP_COUNT) - .skip(1) - .enumerate() - { + let y_over_twist_neg = &q.y_over_twist.negate()?; + for (dbl_idx, bit) in P::ATE_LOOP_COUNT.iter().skip(1).enumerate() { let dc = &q.double_coefficients[dbl_idx]; - let g_rr_at_p = Fp6Var::new( + let g_rr_at_p = Fp6G::<P>::new( &dc.c_l - &dc.c_4c - &dc.c_j * &p.x_twist, &dc.c_h * &p.y_twist, ); f = f.square()? * &g_rr_at_p; - if bit { + let g_rq_at_p; + // Compute l_{R,Q}(P) if bit == 1, and l_{R,-Q}(P) if bit == -1 + if *bit == 1 { + let ac = &q.addition_coefficients[add_idx]; + add_idx += 1; + + g_rq_at_p = Fp6G::<P>::new( + &ac.c_rz * &p.y_twist, + (&q.y_over_twist * &ac.c_rz + &l1_coeff * &ac.c_l1).negate()?, + ); + } else if *bit == -1 { let ac = &q.addition_coefficients[add_idx]; add_idx += 1; - let g_rq_at_p = Fp6Var::new( + g_rq_at_p = Fp6G::<P>::new( &ac.c_rz * &p.y_twist, - (&q.y_over_twist * &ac.c_rz + &(&l1_coeff * &ac.c_l1)).negate()?, + (y_over_twist_neg * &ac.c_rz + &l1_coeff * &ac.c_l1).negate()?, ); - f *= &g_rq_at_p; + } else { + continue; } + + f *= &g_rq_at_p; } if P::ATE_IS_LOOP_COUNT_NEG {
M src/pairing/mod.rs → src/pairing/mod.rs

@@ -1,5 +1,6 @@

use crate::prelude::*; -use ark_ec::PairingEngine; +use ark_ec::pairing::Pairing; +use ark_ec::CurveGroup; use ark_ff::Field; use ark_relations::r1cs::SynthesisError; use core::fmt::Debug;

@@ -13,22 +14,23 @@ pub mod mnt6;

/// Specifies the constraints for computing a pairing in the yybilinear group /// `E`. -pub trait PairingVar<E: PairingEngine, ConstraintF: Field = <E as PairingEngine>::Fq> { +pub trait PairingVar<E: Pairing, ConstraintF: Field = <<E as Pairing>::G1 as CurveGroup>::BaseField> +{ /// An variable representing an element of `G1`. /// This is the R1CS equivalent of `E::G1Projective`. - type G1Var: CurveVar<E::G1Projective, ConstraintF> - + AllocVar<E::G1Projective, ConstraintF> + type G1Var: CurveVar<E::G1, ConstraintF> + + AllocVar<E::G1, ConstraintF> + AllocVar<E::G1Affine, ConstraintF>; /// An variable representing an element of `G2`. /// This is the R1CS equivalent of `E::G2Projective`. - type G2Var: CurveVar<E::G2Projective, ConstraintF> - + AllocVar<E::G2Projective, ConstraintF> + type G2Var: CurveVar<E::G2, ConstraintF> + + AllocVar<E::G2, ConstraintF> + AllocVar<E::G2Affine, ConstraintF>; /// An variable representing an element of `GT`. /// This is the R1CS equivalent of `E::GT`. - type GTVar: FieldVar<E::Fqk, ConstraintF>; + type GTVar: FieldVar<E::TargetField, ConstraintF>; /// An variable representing cached precomputation that can speed up /// pairings computations. This is the R1CS equivalent of
M tests/arithmetic_tests.rs → tests/arithmetic_tests.rs

@@ -1,5 +1,5 @@

use ark_bls12_381::Bls12_381; -use ark_ec::PairingEngine; +use ark_ec::{pairing::Pairing, CurveGroup}; use ark_ff::{BigInteger, PrimeField}; use ark_mnt4_298::MNT4_298; use ark_mnt4_753::MNT4_753;

@@ -673,48 +673,48 @@ }

nonnative_test!( MNT46Small, - <MNT4_298 as PairingEngine>::Fr, - <MNT6_298 as PairingEngine>::Fr + <MNT4_298 as Pairing>::ScalarField, + <MNT6_298 as Pairing>::ScalarField ); nonnative_test!( MNT64Small, - <MNT6_298 as PairingEngine>::Fr, - <MNT4_298 as PairingEngine>::Fr + <MNT6_298 as Pairing>::ScalarField, + <MNT4_298 as Pairing>::ScalarField ); nonnative_test!( MNT46Big, - <MNT4_753 as PairingEngine>::Fr, - <MNT6_753 as PairingEngine>::Fr + <MNT4_753 as Pairing>::ScalarField, + <MNT6_753 as Pairing>::ScalarField ); nonnative_test!( MNT64Big, - <MNT6_753 as PairingEngine>::Fr, - <MNT4_753 as PairingEngine>::Fr + <MNT6_753 as Pairing>::ScalarField, + <MNT4_753 as Pairing>::ScalarField ); nonnative_test!( BLS12MNT4Small, - <Bls12_381 as PairingEngine>::Fr, - <MNT4_298 as PairingEngine>::Fr + <Bls12_381 as Pairing>::ScalarField, + <MNT4_298 as Pairing>::ScalarField ); nonnative_test!( BLS12, - <Bls12_381 as PairingEngine>::Fq, - <Bls12_381 as PairingEngine>::Fr + <<Bls12_381 as Pairing>::G1 as CurveGroup>::BaseField, + <Bls12_381 as Pairing>::ScalarField ); #[cfg(not(ci))] nonnative_test!( MNT6BigMNT4Small, - <MNT6_753 as PairingEngine>::Fr, - <MNT4_298 as PairingEngine>::Fr + <MNT6_753 as Pairing>::ScalarField, + <MNT4_298 as Pairing>::ScalarField ); nonnative_test!( PallasFrMNT6Fr, ark_pallas::Fr, - <MNT6_753 as PairingEngine>::Fr + <MNT6_753 as Pairing>::ScalarField ); nonnative_test!( MNT6FrPallasFr, - <MNT6_753 as PairingEngine>::Fr, + <MNT6_753 as Pairing>::ScalarField, ark_pallas::Fr ); nonnative_test!(PallasFqFr, ark_pallas::Fq, ark_pallas::Fr);