From 819332498605fe4f86aba8c18b170bb1da972e19 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 27 May 2019 17:15:16 +0100 Subject: [PATCH 1/4] Move additive CurveProjective operators to traits --- bellman/src/groth16/tests/dummy_engine.rs | 4 - bellman/src/groth16/verifier.rs | 1 + bellman/src/multiexp.rs | 1 + group/src/lib.rs | 30 ++- pairing/benches/bls12_381/ec.rs | 2 + pairing/src/bls12_381/ec.rs | 236 ++++++++++++++-------- 6 files changed, 173 insertions(+), 101 deletions(-) diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 63aca12f9..f75be5369 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -413,10 +413,6 @@ impl CurveProjective for Fr { self.0 = ::double(self).0; } - fn add_assign(&mut self, other: &Self) { - AddAssign::add_assign(self, other); - } - fn add_assign_mixed(&mut self, other: &Self) { AddAssign::add_assign(self, other); } diff --git a/bellman/src/groth16/verifier.rs b/bellman/src/groth16/verifier.rs index 5bc05810b..3d9ff0881 100644 --- a/bellman/src/groth16/verifier.rs +++ b/bellman/src/groth16/verifier.rs @@ -1,6 +1,7 @@ use ff::PrimeField; use group::{CurveAffine, CurveProjective}; use pairing::{Engine, PairingCurveAffine}; +use std::ops::AddAssign; use super::{PreparedVerifyingKey, Proof, VerifyingKey}; diff --git a/bellman/src/multiexp.rs b/bellman/src/multiexp.rs index b7729a868..3f1ed0bce 100644 --- a/bellman/src/multiexp.rs +++ b/bellman/src/multiexp.rs @@ -5,6 +5,7 @@ use futures::Future; use group::{CurveAffine, CurveProjective}; use std::io; use std::iter; +use std::ops::AddAssign; use std::sync::Arc; use super::SynthesisError; diff --git a/group/src/lib.rs b/group/src/lib.rs index be78b2aef..8d5c405a6 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -5,6 +5,7 @@ use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField}; use rand::RngCore; use std::error::Error; use std::fmt; +use std::ops::{Add, AddAssign, Sub, SubAssign}; pub mod tests; @@ -14,7 +15,24 @@ pub use self::wnaf::Wnaf; /// Projective representation of an elliptic curve point guaranteed to be /// in the correct prime order subgroup. pub trait CurveProjective: - PartialEq + Eq + Sized + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static + PartialEq + + Eq + + Sized + + Copy + + Clone + + Send + + Sync + + fmt::Debug + + fmt::Display + + 'static + + Add + + Sub + + for<'a> Add<&'a Self, Output = Self> + + for<'a> Sub<&'a Self, Output = Self> + + AddAssign + + SubAssign + + for<'a> AddAssign<&'a Self> + + for<'a> SubAssign<&'a Self> { type Engine: ScalarEngine; type Scalar: PrimeField + SqrtField; @@ -44,16 +62,6 @@ pub trait CurveProjective: /// Doubles this element. fn double(&mut self); - /// Adds another element to this element. - fn add_assign(&mut self, other: &Self); - - /// Subtracts another element from this element. - fn sub_assign(&mut self, other: &Self) { - let mut tmp = *other; - tmp.negate(); - self.add_assign(&tmp); - } - /// Adds an affine element to this element. fn add_assign_mixed(&mut self, other: &Self::Affine); diff --git a/pairing/benches/bls12_381/ec.rs b/pairing/benches/bls12_381/ec.rs index 34113629d..5928479d6 100644 --- a/pairing/benches/bls12_381/ec.rs +++ b/pairing/benches/bls12_381/ec.rs @@ -2,6 +2,7 @@ pub(crate) mod g1 { use criterion::{criterion_group, Criterion}; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; + use std::ops::AddAssign; use ff::Field; use group::CurveProjective; @@ -88,6 +89,7 @@ pub(crate) mod g2 { use criterion::{criterion_group, Criterion}; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; + use std::ops::AddAssign; use ff::Field; use group::CurveProjective; diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index 513228934..8e105f290 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -188,6 +188,155 @@ macro_rules! curve_impl { } } + impl<'r> ::std::ops::Add<&'r $projective> for $projective { + type Output = Self; + + #[inline] + fn add(self, other: &Self) -> Self { + let mut ret = self; + ret.add_assign(other); + ret + } + } + + impl ::std::ops::Add for $projective { + type Output = Self; + + #[inline] + fn add(self, other: Self) -> Self { + self + &other + } + } + + impl<'r> ::std::ops::AddAssign<&'r $projective> for $projective { + fn add_assign(&mut self, other: &Self) { + if self.is_zero() { + *self = *other; + return; + } + + if other.is_zero() { + return; + } + + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl + + // Z1Z1 = Z1^2 + let z1z1 = self.z.square(); + + // Z2Z2 = Z2^2 + let z2z2 = other.z.square(); + + // U1 = X1*Z2Z2 + let mut u1 = self.x; + u1.mul_assign(&z2z2); + + // U2 = X2*Z1Z1 + let mut u2 = other.x; + u2.mul_assign(&z1z1); + + // S1 = Y1*Z2*Z2Z2 + let mut s1 = self.y; + s1.mul_assign(&other.z); + s1.mul_assign(&z2z2); + + // S2 = Y2*Z1*Z1Z1 + let mut s2 = other.y; + s2.mul_assign(&self.z); + s2.mul_assign(&z1z1); + + if u1 == u2 && s1 == s2 { + // The two points are equal, so we double. + self.double(); + } else { + // If we're adding -a and a together, self.z becomes zero as H becomes zero. + + // H = U2-U1 + let mut h = u2; + h.sub_assign(&u1); + + // I = (2*H)^2 + let i = h.double().square(); + + // J = H*I + let mut j = h; + j.mul_assign(&i); + + // r = 2*(S2-S1) + let mut r = s2; + r.sub_assign(&s1); + r = r.double(); + + // V = U1*I + let mut v = u1; + v.mul_assign(&i); + + // X3 = r^2 - J - 2*V + self.x = r.square(); + self.x.sub_assign(&j); + self.x.sub_assign(&v); + self.x.sub_assign(&v); + + // Y3 = r*(V - X3) - 2*S1*J + self.y = v; + self.y.sub_assign(&self.x); + self.y.mul_assign(&r); + s1.mul_assign(&j); // S1 = S1 * J * 2 + s1 = s1.double(); + self.y.sub_assign(&s1); + + // Z3 = ((Z1+Z2)^2 - Z1Z1 - Z2Z2)*H + self.z.add_assign(&other.z); + self.z = self.z.square(); + self.z.sub_assign(&z1z1); + self.z.sub_assign(&z2z2); + self.z.mul_assign(&h); + } + } + } + + impl ::std::ops::AddAssign for $projective { + #[inline] + fn add_assign(&mut self, other: Self) { + self.add_assign(&other); + } + } + + impl<'r> ::std::ops::Sub<&'r $projective> for $projective { + type Output = Self; + + #[inline] + fn sub(self, other: &Self) -> Self { + let mut ret = self; + ret.sub_assign(other); + ret + } + } + + impl ::std::ops::Sub for $projective { + type Output = Self; + + #[inline] + fn sub(self, other: Self) -> Self { + self - &other + } + } + + impl<'r> ::std::ops::SubAssign<&'r $projective> for $projective { + fn sub_assign(&mut self, other: &Self) { + let mut tmp = *other; + tmp.negate(); + self.add_assign(&tmp); + } + } + + impl ::std::ops::SubAssign for $projective { + #[inline] + fn sub_assign(&mut self, other: Self) { + self.sub_assign(&other); + } + } + impl CurveProjective for $projective { type Engine = Bls12; type Scalar = $scalarfield; @@ -340,91 +489,6 @@ macro_rules! curve_impl { self.y.sub_assign(&c); } - fn add_assign(&mut self, other: &Self) { - if self.is_zero() { - *self = *other; - return; - } - - if other.is_zero() { - return; - } - - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl - - // Z1Z1 = Z1^2 - let z1z1 = self.z.square(); - - // Z2Z2 = Z2^2 - let z2z2 = other.z.square(); - - // U1 = X1*Z2Z2 - let mut u1 = self.x; - u1.mul_assign(&z2z2); - - // U2 = X2*Z1Z1 - let mut u2 = other.x; - u2.mul_assign(&z1z1); - - // S1 = Y1*Z2*Z2Z2 - let mut s1 = self.y; - s1.mul_assign(&other.z); - s1.mul_assign(&z2z2); - - // S2 = Y2*Z1*Z1Z1 - let mut s2 = other.y; - s2.mul_assign(&self.z); - s2.mul_assign(&z1z1); - - if u1 == u2 && s1 == s2 { - // The two points are equal, so we double. - self.double(); - } else { - // If we're adding -a and a together, self.z becomes zero as H becomes zero. - - // H = U2-U1 - let mut h = u2; - h.sub_assign(&u1); - - // I = (2*H)^2 - let i = h.double().square(); - - // J = H*I - let mut j = h; - j.mul_assign(&i); - - // r = 2*(S2-S1) - let mut r = s2; - r.sub_assign(&s1); - r = r.double(); - - // V = U1*I - let mut v = u1; - v.mul_assign(&i); - - // X3 = r^2 - J - 2*V - self.x = r.square(); - self.x.sub_assign(&j); - self.x.sub_assign(&v); - self.x.sub_assign(&v); - - // Y3 = r*(V - X3) - 2*S1*J - self.y = v; - self.y.sub_assign(&self.x); - self.y.mul_assign(&r); - s1.mul_assign(&j); // S1 = S1 * J * 2 - s1 = s1.double(); - self.y.sub_assign(&s1); - - // Z3 = ((Z1+Z2)^2 - Z1Z1 - Z2Z2)*H - self.z.add_assign(&other.z); - self.z = self.z.square(); - self.z.sub_assign(&z1z1); - self.z.sub_assign(&z2z2); - self.z.mul_assign(&h); - } - } - fn add_assign_mixed(&mut self, other: &Self::Affine) { if other.is_zero() { return; @@ -521,7 +585,7 @@ macro_rules! curve_impl { } if i { - res.add_assign(self); + res.add_assign(&*self); } } From 1a8ec21c032be8f5b8589cd9e56b7e7e8abc39a7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 27 May 2019 17:36:22 +0100 Subject: [PATCH 2/4] Move from Curve*::negate to Neg operator --- bellman/src/groth16/tests/dummy_engine.rs | 8 ----- bellman/src/groth16/verifier.rs | 8 ++--- group/src/lib.rs | 21 +++++++----- group/src/tests/mod.rs | 8 ++--- pairing/src/bls12_381/ec.rs | 42 +++++++++++++++-------- 5 files changed, 46 insertions(+), 41 deletions(-) diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index f75be5369..504030fd7 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -417,10 +417,6 @@ impl CurveProjective for Fr { AddAssign::add_assign(self, other); } - fn negate(&mut self) { - self.0 = self.neg().0; - } - fn mul_assign::Repr>>(&mut self, other: S) { let tmp = Fr::from_repr(other.into()).unwrap(); @@ -499,10 +495,6 @@ impl CurveAffine for Fr { ::is_zero(self) } - fn negate(&mut self) { - self.0 = self.neg().0; - } - fn mul::Repr>>(&self, other: S) -> Self::Projective { let mut res = *self; let tmp = Fr::from_repr(other.into()).unwrap(); diff --git a/bellman/src/groth16/verifier.rs b/bellman/src/groth16/verifier.rs index 3d9ff0881..8ee8a7418 100644 --- a/bellman/src/groth16/verifier.rs +++ b/bellman/src/groth16/verifier.rs @@ -1,17 +1,15 @@ use ff::PrimeField; use group::{CurveAffine, CurveProjective}; use pairing::{Engine, PairingCurveAffine}; -use std::ops::AddAssign; +use std::ops::{AddAssign, Neg}; use super::{PreparedVerifyingKey, Proof, VerifyingKey}; use crate::SynthesisError; pub fn prepare_verifying_key(vk: &VerifyingKey) -> PreparedVerifyingKey { - let mut gamma = vk.gamma_g2; - gamma.negate(); - let mut delta = vk.delta_g2; - delta.negate(); + let gamma = vk.gamma_g2.neg(); + let delta = vk.delta_g2.neg(); PreparedVerifyingKey { alpha_g1_beta_g2: E::pairing(vk.alpha_g1, vk.beta_g2), diff --git a/group/src/lib.rs b/group/src/lib.rs index 8d5c405a6..b2dc410ea 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -5,7 +5,7 @@ use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField}; use rand::RngCore; use std::error::Error; use std::fmt; -use std::ops::{Add, AddAssign, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Neg, Sub, SubAssign}; pub mod tests; @@ -27,6 +27,7 @@ pub trait CurveProjective: + 'static + Add + Sub + + Neg + for<'a> Add<&'a Self, Output = Self> + for<'a> Sub<&'a Self, Output = Self> + AddAssign @@ -65,9 +66,6 @@ pub trait CurveProjective: /// Adds an affine element to this element. fn add_assign_mixed(&mut self, other: &Self::Affine); - /// Negates this element. - fn negate(&mut self); - /// Performs scalar multiplication of this element. fn mul_assign::Repr>>(&mut self, other: S); @@ -86,7 +84,17 @@ pub trait CurveProjective: /// Affine representation of an elliptic curve point guaranteed to be /// in the correct prime order subgroup. pub trait CurveAffine: - Copy + Clone + Sized + Send + Sync + fmt::Debug + fmt::Display + PartialEq + Eq + 'static + Copy + + Clone + + Sized + + Send + + Sync + + fmt::Debug + + fmt::Display + + PartialEq + + Eq + + 'static + + Neg { type Engine: ScalarEngine; type Scalar: PrimeField + SqrtField; @@ -105,9 +113,6 @@ pub trait CurveAffine: /// additive identity. fn is_zero(&self) -> bool; - /// Negates this element. - fn negate(&mut self); - /// Performs scalar multiplication of this element with mixed addition. fn mul::Repr>>(&self, other: S) -> Self::Projective; diff --git a/group/src/tests/mod.rs b/group/src/tests/mod.rs index 949d934f2..e86167b41 100644 --- a/group/src/tests/mod.rs +++ b/group/src/tests/mod.rs @@ -13,8 +13,7 @@ pub fn curve_tests() { // Negation edge case with zero. { - let mut z = G::zero(); - z.negate(); + let z = G::zero().neg(); assert!(z.is_zero()); } @@ -216,8 +215,7 @@ fn random_negation_tests() { t4.add_assign_mixed(&t2.into_affine()); assert!(t4.is_zero()); - t1.negate(); - assert_eq!(t1, t2); + assert_eq!(t1.neg(), t2); } } @@ -440,7 +438,7 @@ fn random_encoding_tests() { let de_compressed = compressed.into_affine().unwrap(); assert_eq!(de_compressed, r); - r.negate(); + r = r.neg(); let compressed = r.into_compressed(); let de_compressed = compressed.into_affine().unwrap(); diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index 8e105f290..b016959d7 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -134,6 +134,19 @@ macro_rules! curve_impl { } } + impl ::std::ops::Neg for $affine { + type Output = Self; + + #[inline] + fn neg(self) -> Self { + let mut ret = self; + if !ret.is_zero() { + ret.y = ret.y.neg(); + } + ret + } + } + impl CurveAffine for $affine { type Engine = Bls12; type Scalar = $scalarfield; @@ -163,12 +176,6 @@ macro_rules! curve_impl { self.mul_bits(bits) } - fn negate(&mut self) { - if !self.is_zero() { - self.y = self.y.neg(); - } - } - fn into_projective(&self) -> $projective { (*self).into() } @@ -188,6 +195,19 @@ macro_rules! curve_impl { } } + impl ::std::ops::Neg for $projective { + type Output = Self; + + #[inline] + fn neg(self) -> Self { + let mut ret = self; + if !ret.is_zero() { + ret.y = ret.y.neg(); + } + ret + } + } + impl<'r> ::std::ops::Add<&'r $projective> for $projective { type Output = Self; @@ -324,9 +344,7 @@ macro_rules! curve_impl { impl<'r> ::std::ops::SubAssign<&'r $projective> for $projective { fn sub_assign(&mut self, other: &Self) { - let mut tmp = *other; - tmp.negate(); - self.add_assign(&tmp); + self.add_assign(&other.neg()); } } @@ -566,12 +584,6 @@ macro_rules! curve_impl { } } - fn negate(&mut self) { - if !self.is_zero() { - self.y = self.y.neg(); - } - } - fn mul_assign::Repr>>(&mut self, other: S) { let mut res = Self::zero(); From d822e34e63c76d1d40257dce9b972679045e7dd4 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 14 Dec 2019 17:15:16 +0000 Subject: [PATCH 3/4] Extract curve operations into default impl traits This makes it possible to implement mixed addition using operator-backed traits without running into type annotation problems. --- group/src/lib.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/group/src/lib.rs b/group/src/lib.rs index b2dc410ea..abda0a6eb 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -12,6 +12,21 @@ pub mod tests; mod wnaf; pub use self::wnaf::Wnaf; +/// A helper trait for types implementing group addition. +pub trait CurveOps: + Add + Sub + AddAssign + SubAssign +{ +} + +impl CurveOps for T where + T: Add + Sub + AddAssign + SubAssign +{ +} + +/// A helper trait for references implementing group addition. +pub trait CurveOpsOwned: for<'r> CurveOps<&'r Rhs, Output> {} +impl CurveOpsOwned for T where T: for<'r> CurveOps<&'r Rhs, Output> {} + /// Projective representation of an elliptic curve point guaranteed to be /// in the correct prime order subgroup. pub trait CurveProjective: @@ -25,15 +40,9 @@ pub trait CurveProjective: + fmt::Debug + fmt::Display + 'static - + Add - + Sub + Neg - + for<'a> Add<&'a Self, Output = Self> - + for<'a> Sub<&'a Self, Output = Self> - + AddAssign - + SubAssign - + for<'a> AddAssign<&'a Self> - + for<'a> SubAssign<&'a Self> + + CurveOps + + CurveOpsOwned { type Engine: ScalarEngine; type Scalar: PrimeField + SqrtField; From 9c485cc97ec2d91dd3aecf7bab33bd964ce2635f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 14 Dec 2019 17:20:47 +0000 Subject: [PATCH 4/4] Move from CurveProjective::add_assign_mixed to traits --- bellman/src/groth16/prover.rs | 28 +-- bellman/src/groth16/tests/dummy_engine.rs | 4 - bellman/src/groth16/verifier.rs | 2 +- bellman/src/multiexp.rs | 65 ++++--- group/src/lib.rs | 5 +- group/src/tests/mod.rs | 38 ++-- pairing/benches/bls12_381/ec.rs | 4 +- pairing/src/bls12_381/ec.rs | 224 ++++++++++++++-------- pairing/src/lib.rs | 10 +- 9 files changed, 225 insertions(+), 155 deletions(-) diff --git a/bellman/src/groth16/prover.rs b/bellman/src/groth16/prover.rs index 3c5b90f11..c31b4db97 100644 --- a/bellman/src/groth16/prover.rs +++ b/bellman/src/groth16/prover.rs @@ -314,34 +314,34 @@ where } let mut g_a = vk.delta_g1.mul(r); - g_a.add_assign_mixed(&vk.alpha_g1); + AddAssign::<&E::G1Affine>::add_assign(&mut g_a, &vk.alpha_g1); let mut g_b = vk.delta_g2.mul(s); - g_b.add_assign_mixed(&vk.beta_g2); + AddAssign::<&E::G2Affine>::add_assign(&mut g_b, &vk.beta_g2); let mut g_c; { let mut rs = r; rs.mul_assign(&s); g_c = vk.delta_g1.mul(rs); - g_c.add_assign(&vk.alpha_g1.mul(s)); - g_c.add_assign(&vk.beta_g1.mul(r)); + AddAssign::<&E::G1>::add_assign(&mut g_c, &vk.alpha_g1.mul(s)); + AddAssign::<&E::G1>::add_assign(&mut g_c, &vk.beta_g1.mul(r)); } let mut a_answer = a_inputs.wait()?; - a_answer.add_assign(&a_aux.wait()?); - g_a.add_assign(&a_answer); + AddAssign::<&E::G1>::add_assign(&mut a_answer, &a_aux.wait()?); + AddAssign::<&E::G1>::add_assign(&mut g_a, &a_answer); a_answer.mul_assign(s); - g_c.add_assign(&a_answer); + AddAssign::<&E::G1>::add_assign(&mut g_c, &a_answer); - let mut b1_answer = b_g1_inputs.wait()?; - b1_answer.add_assign(&b_g1_aux.wait()?); + let mut b1_answer: E::G1 = b_g1_inputs.wait()?; + AddAssign::<&E::G1>::add_assign(&mut b1_answer, &b_g1_aux.wait()?); let mut b2_answer = b_g2_inputs.wait()?; - b2_answer.add_assign(&b_g2_aux.wait()?); + AddAssign::<&E::G2>::add_assign(&mut b2_answer, &b_g2_aux.wait()?); - g_b.add_assign(&b2_answer); + AddAssign::<&E::G2>::add_assign(&mut g_b, &b2_answer); b1_answer.mul_assign(r); - g_c.add_assign(&b1_answer); - g_c.add_assign(&h.wait()?); - g_c.add_assign(&l.wait()?); + AddAssign::<&E::G1>::add_assign(&mut g_c, &b1_answer); + AddAssign::<&E::G1>::add_assign(&mut g_c, &h.wait()?); + AddAssign::<&E::G1>::add_assign(&mut g_c, &l.wait()?); Ok(Proof { a: g_a.into_affine(), diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 504030fd7..65a3ba2ca 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -413,10 +413,6 @@ impl CurveProjective for Fr { self.0 = ::double(self).0; } - fn add_assign_mixed(&mut self, other: &Self) { - AddAssign::add_assign(self, other); - } - fn mul_assign::Repr>>(&mut self, other: S) { let tmp = Fr::from_repr(other.into()).unwrap(); diff --git a/bellman/src/groth16/verifier.rs b/bellman/src/groth16/verifier.rs index 8ee8a7418..598366715 100644 --- a/bellman/src/groth16/verifier.rs +++ b/bellman/src/groth16/verifier.rs @@ -31,7 +31,7 @@ pub fn verify_proof<'a, E: Engine>( let mut acc = pvk.ic[0].into_projective(); for (i, b) in public_inputs.iter().zip(pvk.ic.iter().skip(1)) { - acc.add_assign(&b.mul(i.into_repr())); + AddAssign::<&E::G1>::add_assign(&mut acc, &b.mul(i.into_repr())); } // The original verification equation is: diff --git a/bellman/src/multiexp.rs b/bellman/src/multiexp.rs index 3f1ed0bce..0bc61ba14 100644 --- a/bellman/src/multiexp.rs +++ b/bellman/src/multiexp.rs @@ -19,16 +19,24 @@ pub trait SourceBuilder: Send + Sync + 'static + Clone { /// A source of bases, like an iterator. pub trait Source { - /// Parses the element from the source. Fails if the point is at infinity. - fn add_assign_mixed( - &mut self, - to: &mut ::Projective, - ) -> Result<(), SynthesisError>; + fn next(&mut self) -> Result<&G, SynthesisError>; /// Skips `amt` elements from the source, avoiding deserialization. fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>; } +pub trait AddAssignFromSource: CurveProjective { + /// Parses the element from the source. Fails if the point is at infinity. + fn add_assign_from_source::Affine>>( + &mut self, + source: &mut S, + ) -> Result<(), SynthesisError> { + AddAssign::<&::Affine>::add_assign(self, source.next()?); + Ok(()) + } +} +impl AddAssignFromSource for G where G: CurveProjective {} + impl SourceBuilder for (Arc>, usize) { type Source = (Arc>, usize); @@ -38,10 +46,7 @@ impl SourceBuilder for (Arc>, usize) { } impl Source for (Arc>, usize) { - fn add_assign_mixed( - &mut self, - to: &mut ::Projective, - ) -> Result<(), SynthesisError> { + fn next(&mut self) -> Result<&G, SynthesisError> { if self.0.len() <= self.1 { return Err(io::Error::new( io::ErrorKind::UnexpectedEof, @@ -54,11 +59,10 @@ impl Source for (Arc>, usize) { return Err(SynthesisError::UnexpectedIdentity); } - to.add_assign_mixed(&self.0[self.1]); - + let ret = &self.0[self.1]; self.1 += 1; - Ok(()) + Ok(ret) } fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> { @@ -154,12 +158,12 @@ fn multiexp_inner( mut skip: u32, c: u32, handle_trivial: bool, -) -> Box::Projective, Error = SynthesisError>> +) -> Box> where for<'a> &'a Q: QueryDensity, D: Send + Sync + 'static + Clone + AsRef, - G: CurveAffine, - S: SourceBuilder, + G: CurveProjective, + S: SourceBuilder<::Affine>, { // Perform this region of the multiexp let this = { @@ -169,13 +173,13 @@ where pool.compute(move || { // Accumulate the result - let mut acc = G::Projective::zero(); + let mut acc = G::zero(); // Build a source for the bases let mut bases = bases.new(); // Create space for the buckets - let mut buckets = vec![::Projective::zero(); (1 << c) - 1]; + let mut buckets = vec![G::zero(); (1 << c) - 1]; let zero = ::Fr::zero().into_repr(); let one = ::Fr::one().into_repr(); @@ -187,7 +191,7 @@ where bases.skip(1)?; } else if exp == one { if handle_trivial { - bases.add_assign_mixed(&mut acc)?; + acc.add_assign_from_source(&mut bases)?; } else { bases.skip(1)?; } @@ -197,7 +201,8 @@ where let exp = exp.as_ref()[0] % (1 << c); if exp != 0 { - bases.add_assign_mixed(&mut buckets[(exp - 1) as usize])?; + (&mut buckets[(exp - 1) as usize]) + .add_assign_from_source(&mut bases)?; } else { bases.skip(1)?; } @@ -209,7 +214,7 @@ where // e.g. 3a + 2b + 1c = a + // (a) + b + // ((a) + b) + c - let mut running_sum = G::Projective::zero(); + let mut running_sum = G::zero(); for exp in buckets.into_iter().rev() { running_sum.add_assign(&exp); acc.add_assign(&running_sum); @@ -237,7 +242,7 @@ where c, false, )) - .map(move |(this, mut higher)| { + .map(move |(this, mut higher): (_, G)| { for _ in 0..c { higher.double(); } @@ -257,12 +262,12 @@ pub fn multiexp( bases: S, density_map: D, exponents: Arc::Fr as PrimeField>::Repr>>, -) -> Box::Projective, Error = SynthesisError>> +) -> Box> where for<'a> &'a Q: QueryDensity, D: Send + Sync + 'static + Clone + AsRef, - G: CurveAffine, - S: SourceBuilder, + G: CurveProjective, + S: SourceBuilder<::Affine>, { let c = if exponents.len() < 32 { 3u32 @@ -283,16 +288,16 @@ where #[cfg(feature = "pairing")] #[test] fn test_with_bls12() { - fn naive_multiexp( - bases: Arc>, + fn naive_multiexp( + bases: Arc::Affine>>, exponents: Arc::Repr>>, - ) -> G::Projective { + ) -> G { assert_eq!(bases.len(), exponents.len()); - let mut acc = G::Projective::zero(); + let mut acc = G::zero(); for (base, exp) in bases.iter().zip(exponents.iter()) { - acc.add_assign(&base.mul(*exp)); + AddAssign::<&G>::add_assign(&mut acc, &base.mul(*exp)); } acc @@ -315,7 +320,7 @@ fn test_with_bls12() { .collect::>(), ); - let naive = naive_multiexp(g.clone(), v.clone()); + let naive: ::G1 = naive_multiexp(g.clone(), v.clone()); let pool = Worker::new(); diff --git a/group/src/lib.rs b/group/src/lib.rs index abda0a6eb..b4fb22515 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -43,6 +43,8 @@ pub trait CurveProjective: + Neg + CurveOps + CurveOpsOwned + + CurveOps<::Affine> + + CurveOpsOwned<::Affine> { type Engine: ScalarEngine; type Scalar: PrimeField + SqrtField; @@ -72,9 +74,6 @@ pub trait CurveProjective: /// Doubles this element. fn double(&mut self); - /// Adds an affine element to this element. - fn add_assign_mixed(&mut self, other: &Self::Affine); - /// Performs scalar multiplication of this element. fn mul_assign::Repr>>(&mut self, other: S); diff --git a/group/src/tests/mod.rs b/group/src/tests/mod.rs index e86167b41..c53ba762f 100644 --- a/group/src/tests/mod.rs +++ b/group/src/tests/mod.rs @@ -30,19 +30,19 @@ pub fn curve_tests() { let rcopy = r; r.add_assign(&G::zero()); assert_eq!(r, rcopy); - r.add_assign_mixed(&G::Affine::zero()); + r.add_assign(&G::Affine::zero()); assert_eq!(r, rcopy); let mut z = G::zero(); z.add_assign(&G::zero()); assert!(z.is_zero()); - z.add_assign_mixed(&G::Affine::zero()); + z.add_assign(&G::Affine::zero()); assert!(z.is_zero()); let mut z2 = z; z2.add_assign(&r); - z.add_assign_mixed(&r.into_affine()); + z.add_assign(&r.into_affine()); assert_eq!(z, z2); assert_eq!(z, r); @@ -67,7 +67,7 @@ pub fn curve_tests() { random_negation_tests::(); random_transformation_tests::(); random_wnaf_tests::(); - random_encoding_tests::(); + random_encoding_tests::(); } fn random_wnaf_tests() { @@ -212,7 +212,7 @@ fn random_negation_tests() { assert!(t3.is_zero()); let mut t4 = t1; - t4.add_assign_mixed(&t2.into_affine()); + t4.add_assign(&t2.into_affine()); assert!(t4.is_zero()); assert_eq!(t1.neg(), t2); @@ -242,7 +242,7 @@ fn random_doubling_tests() { tmp2.add_assign(&b); let mut tmp3 = a; - tmp3.add_assign_mixed(&b.into_affine()); + tmp3.add_assign(&b.into_affine()); assert_eq!(tmp1, tmp2); assert_eq!(tmp1, tmp3); @@ -304,7 +304,7 @@ fn random_addition_tests() { aplusa.add_assign(&a); let mut aplusamixed = a; - aplusamixed.add_assign_mixed(&a.into_affine()); + aplusamixed.add_assign(&a.into_affine()); let mut adouble = a; adouble.double(); @@ -334,18 +334,18 @@ fn random_addition_tests() { // (a + b) + c tmp[3] = a_affine.into_projective(); - tmp[3].add_assign_mixed(&b_affine); - tmp[3].add_assign_mixed(&c_affine); + tmp[3].add_assign(&b_affine); + tmp[3].add_assign(&c_affine); // a + (b + c) tmp[4] = b_affine.into_projective(); - tmp[4].add_assign_mixed(&c_affine); - tmp[4].add_assign_mixed(&a_affine); + tmp[4].add_assign(&c_affine); + tmp[4].add_assign(&a_affine); // (a + c) + b tmp[5] = a_affine.into_projective(); - tmp[5].add_assign_mixed(&c_affine); - tmp[5].add_assign_mixed(&b_affine); + tmp[5].add_assign(&c_affine); + tmp[5].add_assign(&b_affine); // Comparisons for i in 0..6 { @@ -411,24 +411,24 @@ fn random_transformation_tests() { } } -fn random_encoding_tests() { +fn random_encoding_tests() { let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, ]); assert_eq!( - G::zero().into_uncompressed().into_affine().unwrap(), - G::zero() + G::Affine::zero().into_uncompressed().into_affine().unwrap(), + G::Affine::zero() ); assert_eq!( - G::zero().into_compressed().into_affine().unwrap(), - G::zero() + G::Affine::zero().into_compressed().into_affine().unwrap(), + G::Affine::zero() ); for _ in 0..1000 { - let mut r = G::Projective::random(&mut rng).into_affine(); + let mut r = G::random(&mut rng).into_affine(); let uncompressed = r.into_uncompressed(); let de_uncompressed = uncompressed.into_affine().unwrap(); diff --git a/pairing/benches/bls12_381/ec.rs b/pairing/benches/bls12_381/ec.rs index 5928479d6..28ce4bf84 100644 --- a/pairing/benches/bls12_381/ec.rs +++ b/pairing/benches/bls12_381/ec.rs @@ -70,7 +70,7 @@ pub(crate) mod g1 { c.bench_function("G1::add_assign_mixed", |b| { b.iter(|| { let mut tmp = v[count].0; - tmp.add_assign_mixed(&v[count].1); + tmp.add_assign(&v[count].1); count = (count + 1) % SAMPLES; tmp }) @@ -157,7 +157,7 @@ pub(crate) mod g2 { c.bench_function("G2::add_assign_mixed", |b| { b.iter(|| { let mut tmp = v[count].0; - tmp.add_assign_mixed(&v[count].1); + tmp.add_assign(&v[count].1); count = (count + 1) % SAMPLES; tmp }) diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index b016959d7..8f8187fd4 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -86,7 +86,7 @@ macro_rules! curve_impl { for i in bits { res.double(); if i { - res.add_assign_mixed(self) + res.add_assign(self) } } res @@ -355,6 +355,149 @@ macro_rules! curve_impl { } } + impl<'r> ::std::ops::Add<&'r <$projective as CurveProjective>::Affine> for $projective { + type Output = Self; + + #[inline] + fn add(self, other: &<$projective as CurveProjective>::Affine) -> Self { + let mut ret = self; + ret.add_assign(other); + ret + } + } + + impl ::std::ops::Add<<$projective as CurveProjective>::Affine> for $projective { + type Output = Self; + + #[inline] + fn add(self, other: <$projective as CurveProjective>::Affine) -> Self { + self + &other + } + } + + impl<'r> ::std::ops::AddAssign<&'r <$projective as CurveProjective>::Affine> + for $projective + { + fn add_assign(&mut self, other: &<$projective as CurveProjective>::Affine) { + if other.is_zero() { + return; + } + + if self.is_zero() { + self.x = other.x; + self.y = other.y; + self.z = $basefield::one(); + return; + } + + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + + // Z1Z1 = Z1^2 + let z1z1 = self.z.square(); + + // U2 = X2*Z1Z1 + let mut u2 = other.x; + u2.mul_assign(&z1z1); + + // S2 = Y2*Z1*Z1Z1 + let mut s2 = other.y; + s2.mul_assign(&self.z); + s2.mul_assign(&z1z1); + + if self.x == u2 && self.y == s2 { + // The two points are equal, so we double. + self.double(); + } else { + // If we're adding -a and a together, self.z becomes zero as H becomes zero. + + // H = U2-X1 + let mut h = u2; + h.sub_assign(&self.x); + + // HH = H^2 + let hh = h.square(); + + // I = 4*HH + let i = hh.double().double(); + + // J = H*I + let mut j = h; + j.mul_assign(&i); + + // r = 2*(S2-Y1) + let mut r = s2; + r.sub_assign(&self.y); + r = r.double(); + + // V = X1*I + let mut v = self.x; + v.mul_assign(&i); + + // X3 = r^2 - J - 2*V + self.x = r.square(); + self.x.sub_assign(&j); + self.x.sub_assign(&v); + self.x.sub_assign(&v); + + // Y3 = r*(V-X3)-2*Y1*J + j.mul_assign(&self.y); // J = 2*Y1*J + j = j.double(); + self.y = v; + self.y.sub_assign(&self.x); + self.y.mul_assign(&r); + self.y.sub_assign(&j); + + // Z3 = (Z1+H)^2-Z1Z1-HH + self.z.add_assign(&h); + self.z = self.z.square(); + self.z.sub_assign(&z1z1); + self.z.sub_assign(&hh); + } + } + } + + impl ::std::ops::AddAssign<<$projective as CurveProjective>::Affine> for $projective { + #[inline] + fn add_assign(&mut self, other: <$projective as CurveProjective>::Affine) { + self.add_assign(&other); + } + } + + impl<'r> ::std::ops::Sub<&'r <$projective as CurveProjective>::Affine> for $projective { + type Output = Self; + + #[inline] + fn sub(self, other: &<$projective as CurveProjective>::Affine) -> Self { + let mut ret = self; + ret.sub_assign(other); + ret + } + } + + impl ::std::ops::Sub<<$projective as CurveProjective>::Affine> for $projective { + type Output = Self; + + #[inline] + fn sub(self, other: <$projective as CurveProjective>::Affine) -> Self { + self - &other + } + } + + impl<'r> ::std::ops::SubAssign<&'r <$projective as CurveProjective>::Affine> + for $projective + { + fn sub_assign(&mut self, other: &<$projective as CurveProjective>::Affine) { + self.add_assign(&other.neg()); + } + } + + impl ::std::ops::SubAssign<<$projective as CurveProjective>::Affine> for $projective { + #[inline] + fn sub_assign(&mut self, other: <$projective as CurveProjective>::Affine) { + self.sub_assign(&other); + } + } + impl CurveProjective for $projective { type Engine = Bls12; type Scalar = $scalarfield; @@ -507,83 +650,6 @@ macro_rules! curve_impl { self.y.sub_assign(&c); } - fn add_assign_mixed(&mut self, other: &Self::Affine) { - if other.is_zero() { - return; - } - - if self.is_zero() { - self.x = other.x; - self.y = other.y; - self.z = $basefield::one(); - return; - } - - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl - - // Z1Z1 = Z1^2 - let z1z1 = self.z.square(); - - // U2 = X2*Z1Z1 - let mut u2 = other.x; - u2.mul_assign(&z1z1); - - // S2 = Y2*Z1*Z1Z1 - let mut s2 = other.y; - s2.mul_assign(&self.z); - s2.mul_assign(&z1z1); - - if self.x == u2 && self.y == s2 { - // The two points are equal, so we double. - self.double(); - } else { - // If we're adding -a and a together, self.z becomes zero as H becomes zero. - - // H = U2-X1 - let mut h = u2; - h.sub_assign(&self.x); - - // HH = H^2 - let hh = h.square(); - - // I = 4*HH - let i = hh.double().double(); - - // J = H*I - let mut j = h; - j.mul_assign(&i); - - // r = 2*(S2-Y1) - let mut r = s2; - r.sub_assign(&self.y); - r = r.double(); - - // V = X1*I - let mut v = self.x; - v.mul_assign(&i); - - // X3 = r^2 - J - 2*V - self.x = r.square(); - self.x.sub_assign(&j); - self.x.sub_assign(&v); - self.x.sub_assign(&v); - - // Y3 = r*(V-X3)-2*Y1*J - j.mul_assign(&self.y); // J = 2*Y1*J - j = j.double(); - self.y = v; - self.y.sub_assign(&self.x); - self.y.mul_assign(&r); - self.y.sub_assign(&j); - - // Z3 = (Z1+H)^2-Z1Z1-HH - self.z.add_assign(&h); - self.z = self.z.square(); - self.z.sub_assign(&z1z1); - self.z.sub_assign(&hh); - } - } - fn mul_assign::Repr>>(&mut self, other: S) { let mut res = Self::zero(); @@ -1334,7 +1400,7 @@ pub mod g1 { assert_eq!(tmp1, c.into_projective()); let mut tmp2 = a.into_projective(); - tmp2.add_assign_mixed(&b); + tmp2.add_assign(&b); assert_eq!(tmp2.into_affine(), c); assert_eq!(tmp2, c.into_projective()); } diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index bd060a12f..0081d811e 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -21,7 +21,7 @@ pub mod tests; pub mod bls12_381; use ff::{Field, PrimeField, ScalarEngine, SqrtField}; -use group::{CurveAffine, CurveProjective}; +use group::{CurveAffine, CurveOps, CurveOpsOwned, CurveProjective}; use subtle::CtOption; /// An "engine" is a collection of types (fields, elliptic curve groups, etc.) @@ -30,7 +30,9 @@ use subtle::CtOption; pub trait Engine: ScalarEngine { /// The projective representation of an element in G1. type G1: CurveProjective - + From; + + From + + CurveOps + + CurveOpsOwned; /// The affine representation of an element in G1. type G1Affine: PairingCurveAffine< @@ -44,7 +46,9 @@ pub trait Engine: ScalarEngine { /// The projective representation of an element in G2. type G2: CurveProjective - + From; + + From + + CurveOps + + CurveOpsOwned; /// The affine representation of an element in G2. type G2Affine: PairingCurveAffine<