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 63aca12f9..65a3ba2ca 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -413,18 +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); - } - - 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(); @@ -503,10 +491,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 5bc05810b..598366715 100644 --- a/bellman/src/groth16/verifier.rs +++ b/bellman/src/groth16/verifier.rs @@ -1,16 +1,15 @@ use ff::PrimeField; use group::{CurveAffine, CurveProjective}; use pairing::{Engine, PairingCurveAffine}; +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), @@ -32,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 b7729a868..0bc61ba14 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; @@ -18,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); @@ -37,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, @@ -53,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> { @@ -153,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 = { @@ -168,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(); @@ -186,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)?; } @@ -196,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)?; } @@ -208,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); @@ -236,7 +242,7 @@ where c, false, )) - .map(move |(this, mut higher)| { + .map(move |(this, mut higher): (_, G)| { for _ in 0..c { higher.double(); } @@ -256,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 @@ -282,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 @@ -314,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 be78b2aef..b4fb22515 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -5,16 +5,46 @@ use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField}; use rand::RngCore; use std::error::Error; use std::fmt; +use std::ops::{Add, AddAssign, Neg, Sub, SubAssign}; 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: - PartialEq + Eq + Sized + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static + PartialEq + + Eq + + Sized + + Copy + + Clone + + Send + + Sync + + fmt::Debug + + fmt::Display + + 'static + + Neg + + CurveOps + + CurveOpsOwned + + CurveOps<::Affine> + + CurveOpsOwned<::Affine> { type Engine: ScalarEngine; type Scalar: PrimeField + SqrtField; @@ -44,22 +74,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); - - /// Negates this element. - fn negate(&mut self); - /// Performs scalar multiplication of this element. fn mul_assign::Repr>>(&mut self, other: S); @@ -78,7 +92,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; @@ -97,9 +121,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..c53ba762f 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()); } @@ -31,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); @@ -68,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() { @@ -213,11 +212,10 @@ 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()); - t1.negate(); - assert_eq!(t1, t2); + assert_eq!(t1.neg(), t2); } } @@ -244,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); @@ -306,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(); @@ -336,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 { @@ -413,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(); @@ -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/benches/bls12_381/ec.rs b/pairing/benches/bls12_381/ec.rs index 34113629d..28ce4bf84 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; @@ -69,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 }) @@ -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; @@ -155,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 513228934..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 @@ -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,309 @@ 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; + + #[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) { + self.add_assign(&other.neg()); + } + } + + impl ::std::ops::SubAssign for $projective { + #[inline] + fn sub_assign(&mut self, other: Self) { + self.sub_assign(&other); + } + } + + 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; @@ -340,174 +650,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; - } - - 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 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(); @@ -521,7 +663,7 @@ macro_rules! curve_impl { } if i { - res.add_assign(self); + res.add_assign(&*self); } } @@ -1258,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<