Merge pull request #193 from str4d/group-std-ops

Move Group operations to operator-backed traits
This commit is contained in:
str4d 2020-01-28 17:41:50 +00:00 committed by GitHub
commit 702b5e5d8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 448 additions and 292 deletions

View File

@ -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(),

View File

@ -413,18 +413,6 @@ impl CurveProjective for Fr {
self.0 = <Fr as Field>::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<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S) {
let tmp = Fr::from_repr(other.into()).unwrap();
@ -503,10 +491,6 @@ impl CurveAffine for Fr {
<Fr as Field>::is_zero(self)
}
fn negate(&mut self) {
self.0 = self.neg().0;
}
fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective {
let mut res = *self;
let tmp = Fr::from_repr(other.into()).unwrap();

View File

@ -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<E: Engine>(vk: &VerifyingKey<E>) -> PreparedVerifyingKey<E> {
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:

View File

@ -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<G: CurveAffine>: Send + Sync + 'static + Clone {
/// A source of bases, like an iterator.
pub trait Source<G: CurveAffine> {
/// Parses the element from the source. Fails if the point is at infinity.
fn add_assign_mixed(
&mut self,
to: &mut <G as CurveAffine>::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<S: Source<<Self as CurveProjective>::Affine>>(
&mut self,
source: &mut S,
) -> Result<(), SynthesisError> {
AddAssign::<&<Self as CurveProjective>::Affine>::add_assign(self, source.next()?);
Ok(())
}
}
impl<G> AddAssignFromSource for G where G: CurveProjective {}
impl<G: CurveAffine> SourceBuilder<G> for (Arc<Vec<G>>, usize) {
type Source = (Arc<Vec<G>>, usize);
@ -37,10 +46,7 @@ impl<G: CurveAffine> SourceBuilder<G> for (Arc<Vec<G>>, usize) {
}
impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
fn add_assign_mixed(
&mut self,
to: &mut <G as CurveAffine>::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<G: CurveAffine> Source<G> for (Arc<Vec<G>>, 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<Q, D, G, S>(
mut skip: u32,
c: u32,
handle_trivial: bool,
) -> Box<dyn Future<Item = <G as CurveAffine>::Projective, Error = SynthesisError>>
) -> Box<dyn Future<Item = G, Error = SynthesisError>>
where
for<'a> &'a Q: QueryDensity,
D: Send + Sync + 'static + Clone + AsRef<Q>,
G: CurveAffine,
S: SourceBuilder<G>,
G: CurveProjective,
S: SourceBuilder<<G as CurveProjective>::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![<G as CurveAffine>::Projective::zero(); (1 << c) - 1];
let mut buckets = vec![G::zero(); (1 << c) - 1];
let zero = <G::Engine as ScalarEngine>::Fr::zero().into_repr();
let one = <G::Engine as ScalarEngine>::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<Q, D, G, S>(
bases: S,
density_map: D,
exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>,
) -> Box<dyn Future<Item = <G as CurveAffine>::Projective, Error = SynthesisError>>
) -> Box<dyn Future<Item = G, Error = SynthesisError>>
where
for<'a> &'a Q: QueryDensity,
D: Send + Sync + 'static + Clone + AsRef<Q>,
G: CurveAffine,
S: SourceBuilder<G>,
G: CurveProjective,
S: SourceBuilder<<G as CurveProjective>::Affine>,
{
let c = if exponents.len() < 32 {
3u32
@ -282,16 +288,16 @@ where
#[cfg(feature = "pairing")]
#[test]
fn test_with_bls12() {
fn naive_multiexp<G: CurveAffine>(
bases: Arc<Vec<G>>,
fn naive_multiexp<G: CurveProjective>(
bases: Arc<Vec<<G as CurveProjective>::Affine>>,
exponents: Arc<Vec<<G::Scalar as PrimeField>::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::<Vec<_>>(),
);
let naive = naive_multiexp(g.clone(), v.clone());
let naive: <Bls12 as Engine>::G1 = naive_multiexp(g.clone(), v.clone());
let pool = Worker::new();

View File

@ -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<Rhs = Self, Output = Self>:
Add<Rhs, Output = Output> + Sub<Rhs, Output = Output> + AddAssign<Rhs> + SubAssign<Rhs>
{
}
impl<T, Rhs, Output> CurveOps<Rhs, Output> for T where
T: Add<Rhs, Output = Output> + Sub<Rhs, Output = Output> + AddAssign<Rhs> + SubAssign<Rhs>
{
}
/// A helper trait for references implementing group addition.
pub trait CurveOpsOwned<Rhs = Self, Output = Self>: for<'r> CurveOps<&'r Rhs, Output> {}
impl<T, Rhs, Output> CurveOpsOwned<Rhs, Output> 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<Output = Self>
+ CurveOps
+ CurveOpsOwned
+ CurveOps<<Self as CurveProjective>::Affine>
+ CurveOpsOwned<<Self as CurveProjective>::Affine>
{
type Engine: ScalarEngine<Fr = Self::Scalar>;
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<S: Into<<Self::Scalar as PrimeField>::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<Output = Self>
{
type Engine: ScalarEngine<Fr = Self::Scalar>;
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<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective;

View File

@ -13,8 +13,7 @@ pub fn curve_tests<G: CurveProjective>() {
// 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<G: CurveProjective>() {
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<G: CurveProjective>() {
random_negation_tests::<G>();
random_transformation_tests::<G>();
random_wnaf_tests::<G>();
random_encoding_tests::<G::Affine>();
random_encoding_tests::<G>();
}
fn random_wnaf_tests<G: CurveProjective>() {
@ -213,11 +212,10 @@ fn random_negation_tests<G: CurveProjective>() {
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<G: CurveProjective>() {
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<G: CurveProjective>() {
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<G: CurveProjective>() {
// (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<G: CurveProjective>() {
}
}
fn random_encoding_tests<G: CurveAffine>() {
fn random_encoding_tests<G: CurveProjective>() {
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<G: CurveAffine>() {
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();

View File

@ -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
})

View File

@ -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<S: Into<<Self::Scalar as PrimeField>::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());
}

View File

@ -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<Engine = Self, Base = Self::Fq, Scalar = Self::Fr, Affine = Self::G1Affine>
+ From<Self::G1Affine>;
+ From<Self::G1Affine>
+ CurveOps<Self::G1Affine>
+ CurveOpsOwned<Self::G1Affine>;
/// 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<Engine = Self, Base = Self::Fqe, Scalar = Self::Fr, Affine = Self::G2Affine>
+ From<Self::G2Affine>;
+ From<Self::G2Affine>
+ CurveOps<Self::G2Affine>
+ CurveOpsOwned<Self::G2Affine>;
/// The affine representation of an element in G2.
type G2Affine: PairingCurveAffine<