Skip to content

Commit

Permalink
Add AdditiveGroup trait + Field: AdditiveGroup (#577)
Browse files Browse the repository at this point in the history
* Add AdditiveGroup trait + Field: AdditiveGroup. This trait now integrates ZERO, double, double_in_place, and negate. Fix doctests accordingly (#507)
* Fix disambiguation of what is a ScalarField in bench-templates. Remove `ScalarField` from `CurveGroup`

---------

Co-authored-by: Pratyush Mishra <[email protected]>
  • Loading branch information
mmaker and Pratyush authored May 10, 2023
1 parent 2f9556f commit ab13aa0
Show file tree
Hide file tree
Showing 35 changed files with 326 additions and 239 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Breaking changes

- [\#577](https://github.com/arkworks-rs/algebra/pull/577) (`ark-ff`, `ark-ec`) Add `AdditiveGroup`, a trait for additive groups (equipped with scalar field).
- [\#593](https://github.com/arkworks-rs/algebra/pull/593) (`ark-ec`) Change `AffineRepr::xy()` to return owned values.

### Features
Expand Down
9 changes: 5 additions & 4 deletions bench-templates/src/macros/ec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ macro_rules! ec_bench {
($curve_name:expr, $Group:ident) => {
$crate::paste! {
mod [<$Group:lower>] {
use ark_ec::Group;
use ark_ec::PrimeGroup;
use super::*;

type Scalar = <$Group as Group>::ScalarField;
type Scalar = <$Group as PrimeGroup>::ScalarField;
fn rand(c: &mut $crate::criterion::Criterion) {
let name = format!("{}::{}", $curve_name, stringify!($Group));
use ark_std::UniformRand;
Expand All @@ -18,11 +18,12 @@ macro_rules! ec_bench {
}

fn arithmetic(c: &mut $crate::criterion::Criterion) {
use ark_ec::{CurveGroup, Group};
use ark_ff::AdditiveGroup;
use ark_ec::{CurveGroup, PrimeGroup};
use ark_std::UniformRand;
let name = format!("{}::{}", $curve_name, stringify!($Group));

type Scalar = <$Group as Group>::ScalarField;
type Scalar = <$Group as PrimeGroup>::ScalarField;
const SAMPLES: usize = 1000;
let mut rng = ark_std::test_rng();
let mut arithmetic =
Expand Down
2 changes: 2 additions & 0 deletions bench-templates/src/macros/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ macro_rules! f_bench {
macro_rules! field_common {
($bench_group_name:expr, $F:ident) => {
fn arithmetic(c: &mut $crate::criterion::Criterion) {
use ark_ff::AdditiveGroup;

let name = format!("{}::{}", $bench_group_name, stringify!($F));
const SAMPLES: usize = 1000;
let mut rng = ark_std::test_rng();
Expand Down
18 changes: 9 additions & 9 deletions ec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ Implementations of particular curves using these curve models can be found in [`

### The `Group` trait

Many cryptographic protocols use as core building-blocks prime-order groups. The [`Group`](https://github.com/arkworks-rs/algebra/blob/master/ec/src/lib.rs) trait is an abstraction that represents elements of such abelian prime-order groups. It provides methods for performing common operations on group elements:
Many cryptographic protocols use as core building-blocks prime-order groups. The [`PrimeGroup`](https://github.com/arkworks-rs/algebra/blob/master/ec/src/lib.rs) trait is an abstraction that represents elements of such abelian prime-order groups. It provides methods for performing common operations on group elements:

```rust
use ark_ec::Group;
use ark_ec::{AdditiveGroup, PrimeGroup};
use ark_ff::{PrimeField, Field};
// We'll use the BLS12-381 G1 curve for this example.
// This group has a prime order `r`, and is associated with a prime field `Fr`.
Expand Down Expand Up @@ -49,12 +49,12 @@ assert_eq!(f, c);

## Scalar multiplication

While the `Group` trait already produces scalar multiplication routines, in many cases one can take advantage of
While the `PrimeGroup` trait already produces scalar multiplication routines, in many cases one can take advantage of
the group structure to perform scalar multiplication more efficiently. To allow such specialization, `ark-ec` provides
the `ScalarMul` and `VariableBaseMSM` traits. The latter trait computes an "inner product" between a vector of scalars `s` and a vector of group elements `g`. That is, it computes `s.iter().zip(g).map(|(s, g)| g * s).sum()`.

```rust
use ark_ec::{Group, VariableBaseMSM};
use ark_ec::{PrimeGroup, VariableBaseMSM};
use ark_ff::{PrimeField, Field};
// We'll use the BLS12-381 G1 curve for this example.
// This group has a prime order `r`, and is associated with a prime field `Fr`.
Expand All @@ -72,7 +72,7 @@ let s2 = ScalarField::rand(&mut rng);
// Note that we're using the `GAffine` type here, as opposed to `G`.
// This is because MSMs are more efficient when the group elements are in affine form. (See below for why.)
//
// The `VariableBaseMSM` trait allows specializing the input group element representation to allow
// The `VariableBaseMSM` trait allows specializing the input group element representation to allow
// for more efficient implementations.
let r = G::msm(&[a, b], &[s1, s2]).unwrap();
assert_eq!(r, a * s1 + b * s2);
Expand All @@ -90,7 +90,7 @@ but is slower for most arithmetic operations. Let's explore how and when to use
these:

```rust
use ark_ec::{AffineRepr, Group, CurveGroup, VariableBaseMSM};
use ark_ec::{AdditiveGroup, AffineRepr, PrimeGroup, CurveGroup, VariableBaseMSM};
use ark_ff::{PrimeField, Field};
use ark_test_curves::bls12_381::{G1Projective as G, G1Affine as GAffine, Fr as ScalarField};
use ark_std::{Zero, UniformRand};
Expand All @@ -105,9 +105,9 @@ assert_eq!(a_aff, a);
// We can also convert back to the `CurveGroup` representation:
assert_eq!(a, a_aff.into_group());

// As a general rule, most group operations are slower when elements
// are represented as `AffineRepr`. However, adding an `AffineRepr`
// point to a `CurveGroup` one is usually slightly more efficient than
// As a general rule, most group operations are slower when elements
// are represented as `AffineRepr`. However, adding an `AffineRepr`
// point to a `CurveGroup` one is usually slightly more efficient than
// adding two `CurveGroup` points.
let d = a + a_aff;
assert_eq!(d, a.double());
Expand Down
58 changes: 8 additions & 50 deletions ec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{
fmt::{Debug, Display},
hash::Hash,
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
ops::{Add, AddAssign, Mul, MulAssign},
vec::Vec,
};
use num_traits::Zero;
pub use scalar_mul::{variable_base::VariableBaseMSM, ScalarMul};
use zeroize::Zeroize;

pub use ark_ff::AdditiveGroup;

pub mod models;
pub use self::models::*;

Expand All @@ -47,57 +48,14 @@ pub mod hashing;
pub mod pairing;

/// Represents (elements of) a group of prime order `r`.
pub trait Group:
Eq
+ 'static
+ Sized
+ CanonicalSerialize
+ CanonicalDeserialize
+ Copy
+ Clone
+ Default
+ Send
+ Sync
+ Hash
+ Debug
+ Display
+ UniformRand
+ Zeroize
+ Zero
+ Neg<Output = Self>
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Mul<<Self as Group>::ScalarField, Output = Self>
+ AddAssign<Self>
+ SubAssign<Self>
+ MulAssign<<Self as Group>::ScalarField>
+ for<'a> Add<&'a Self, Output = Self>
+ for<'a> Sub<&'a Self, Output = Self>
+ for<'a> Mul<&'a <Self as Group>::ScalarField, Output = Self>
+ for<'a> AddAssign<&'a Self>
+ for<'a> SubAssign<&'a Self>
+ for<'a> MulAssign<&'a <Self as Group>::ScalarField>
+ core::iter::Sum<Self>
+ for<'a> core::iter::Sum<&'a Self>
{
pub trait PrimeGroup: AdditiveGroup<Scalar = Self::ScalarField> {
/// The scalar field `F_r`, where `r` is the order of this group.
type ScalarField: PrimeField;

/// Returns a fixed generator of this group.
#[must_use]
fn generator() -> Self;

/// Doubles `self`.
#[must_use]
fn double(&self) -> Self {
let mut copy = *self;
copy.double_in_place();
copy
}

/// Double `self` in place.
fn double_in_place(&mut self) -> &mut Self;

/// Performs scalar multiplication of this element.
fn mul_bigint(&self, other: impl AsRef<[u64]>) -> Self;

Expand All @@ -121,7 +79,7 @@ pub trait Group:
///
/// The point is guaranteed to be in the correct prime order subgroup.
pub trait CurveGroup:
Group
PrimeGroup
+ Add<Self::Affine, Output = Self>
+ AddAssign<Self::Affine>
// + for<'a> Add<&'a Self::Affine, Output = Self>
Expand Down Expand Up @@ -278,7 +236,7 @@ where
Self::E2: MulAssign<<Self::E1 as CurveGroup>::BaseField>,
{
type E1: CurveGroup<
BaseField = <Self::E2 as Group>::ScalarField,
BaseField = <Self::E2 as PrimeGroup>::ScalarField,
ScalarField = <Self::E2 as CurveGroup>::BaseField,
>;
type E2: CurveGroup;
Expand All @@ -289,12 +247,12 @@ pub trait PairingFriendlyCycle: CurveCycle {
type Engine1: pairing::Pairing<
G1 = Self::E1,
G1Affine = <Self::E1 as CurveGroup>::Affine,
ScalarField = <Self::E1 as Group>::ScalarField,
ScalarField = <Self::E1 as PrimeGroup>::ScalarField,
>;

type Engine2: pairing::Pairing<
G1 = Self::E2,
G1Affine = <Self::E2 as CurveGroup>::Affine,
ScalarField = <Self::E2 as Group>::ScalarField,
ScalarField = <Self::E2 as PrimeGroup>::ScalarField,
>;
}
2 changes: 1 addition & 1 deletion ec/src/models/bls12/g2.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use ark_ff::{BitIteratorBE, Field, Fp2};
use ark_ff::{AdditiveGroup, BitIteratorBE, Field, Fp2};
use ark_serialize::*;
use ark_std::{vec::Vec, One};

Expand Down
5 changes: 4 additions & 1 deletion ec/src/models/bn/g2.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use ark_ff::fields::{Field, Fp2};
use ark_ff::{
fields::{Field, Fp2},
AdditiveGroup,
};
use ark_serialize::*;
use ark_std::vec::Vec;
use num_traits::One;
Expand Down
2 changes: 1 addition & 1 deletion ec/src/models/bw6/g2.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use ark_ff::{BitIteratorBE, Field};
use ark_ff::{AdditiveGroup, BitIteratorBE, Field};
use ark_serialize::*;
use ark_std::vec::Vec;
use num_traits::One;
Expand Down
2 changes: 1 addition & 1 deletion ec/src/models/mnt4/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
use ark_ff::{
fp2::{Fp2, Fp2Config},
fp4::{Fp4, Fp4Config},
CyclotomicMultSubgroup, Field, PrimeField,
AdditiveGroup, CyclotomicMultSubgroup, Field, PrimeField,
};
use itertools::Itertools;
use num_traits::{One, Zero};
Expand Down
4 changes: 1 addition & 3 deletions ec/src/models/mnt6/g2.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use core::ops::Neg;

use crate::{
mnt6::MNT6Config,
models::mnt6::MNT6,
Expand All @@ -8,7 +6,7 @@ use crate::{
};
use ark_ff::fields::{Field, Fp3};
use ark_serialize::*;
use ark_std::vec::Vec;
use ark_std::{ops::Neg, vec::Vec};
use num_traits::One;

pub type G2Affine<P> = Affine<<P as MNT6Config>::G2Config>;
Expand Down
2 changes: 1 addition & 1 deletion ec/src/models/mnt6/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
use ark_ff::{
fp3::{Fp3, Fp3Config},
fp6_2over3::{Fp6, Fp6Config},
CyclotomicMultSubgroup, Field, PrimeField,
AdditiveGroup, CyclotomicMultSubgroup, Field, PrimeField,
};
use itertools::Itertools;
use num_traits::{One, Zero};
Expand Down
2 changes: 1 addition & 1 deletion ec/src/models/short_weierstrass/affine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use ark_std::{
One, Zero,
};

use ark_ff::{fields::Field, PrimeField, ToConstraintField, UniformRand};
use ark_ff::{fields::Field, AdditiveGroup, PrimeField, ToConstraintField, UniformRand};

use zeroize::Zeroize;

Expand Down
23 changes: 15 additions & 8 deletions ec/src/models/short_weierstrass/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use ark_std::{
One, Zero,
};

use ark_ff::{fields::Field, PrimeField, ToConstraintField, UniformRand};
use ark_ff::{fields::Field, AdditiveGroup, PrimeField, ToConstraintField, UniformRand};

use zeroize::Zeroize;

Expand All @@ -25,7 +25,7 @@ use rayon::prelude::*;
use super::{Affine, SWCurveConfig};
use crate::{
scalar_mul::{variable_base::VariableBaseMSM, ScalarMul},
AffineRepr, CurveGroup, Group,
AffineRepr, CurveGroup, PrimeGroup,
};

/// Jacobian coordinates for a point on an elliptic curve in short Weierstrass
Expand Down Expand Up @@ -160,13 +160,11 @@ impl<P: SWCurveConfig> Zero for Projective<P> {
}
}

impl<P: SWCurveConfig> Group for Projective<P> {
type ScalarField = P::ScalarField;
impl<P: SWCurveConfig> AdditiveGroup for Projective<P> {
type Scalar = P::ScalarField;

#[inline]
fn generator() -> Self {
Affine::generator().into()
}
const ZERO: Self =
Self::new_unchecked(P::BaseField::ONE, P::BaseField::ONE, P::BaseField::ZERO);

/// Sets `self = 2 * self`. Note that Jacobian formulae are incomplete, and
/// so doubling cannot be computed as `self + self`. Instead, this
Expand Down Expand Up @@ -273,6 +271,15 @@ impl<P: SWCurveConfig> Group for Projective<P> {
self
}
}
}

impl<P: SWCurveConfig> PrimeGroup for Projective<P> {
type ScalarField = P::ScalarField;

#[inline]
fn generator() -> Self {
Affine::generator().into()
}

#[inline]
fn mul_bigint(&self, other: impl AsRef<[u64]>) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion ec/src/models/short_weierstrass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ark_serialize::{
};
use ark_std::io::{Read, Write};

use ark_ff::fields::Field;
use ark_ff::{fields::Field, AdditiveGroup};

use crate::{
scalar_mul::{
Expand Down
2 changes: 1 addition & 1 deletion ec/src/models/twisted_edwards/affine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use ark_std::{
use num_traits::{One, Zero};
use zeroize::Zeroize;

use ark_ff::{fields::Field, PrimeField, ToConstraintField, UniformRand};
use ark_ff::{fields::Field, AdditiveGroup, PrimeField, ToConstraintField, UniformRand};

use super::{Projective, TECurveConfig, TEFlags};
use crate::AffineRepr;
Expand Down
25 changes: 18 additions & 7 deletions ec/src/models/twisted_edwards/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use ark_std::{
One, Zero,
};

use ark_ff::{fields::Field, PrimeField, ToConstraintField, UniformRand};
use ark_ff::{fields::Field, AdditiveGroup, PrimeField, ToConstraintField, UniformRand};

use zeroize::Zeroize;

Expand All @@ -25,7 +25,7 @@ use rayon::prelude::*;
use super::{Affine, MontCurveConfig, TECurveConfig};
use crate::{
scalar_mul::{variable_base::VariableBaseMSM, ScalarMul},
AffineRepr, CurveGroup, Group,
AffineRepr, CurveGroup, PrimeGroup,
};

/// `Projective` implements Extended Twisted Edwards Coordinates
Expand Down Expand Up @@ -150,12 +150,15 @@ impl<P: TECurveConfig> Zero for Projective<P> {
}
}

impl<P: TECurveConfig> Group for Projective<P> {
type ScalarField = P::ScalarField;
impl<P: TECurveConfig> AdditiveGroup for Projective<P> {
type Scalar = P::ScalarField;

fn generator() -> Self {
Affine::generator().into()
}
const ZERO: Self = Self::new_unchecked(
P::BaseField::ZERO,
P::BaseField::ONE,
P::BaseField::ZERO,
P::BaseField::ONE,
);

fn double_in_place(&mut self) -> &mut Self {
// See "Twisted Edwards Curves Revisited"
Expand Down Expand Up @@ -190,6 +193,14 @@ impl<P: TECurveConfig> Group for Projective<P> {

self
}
}

impl<P: TECurveConfig> PrimeGroup for Projective<P> {
type ScalarField = P::ScalarField;

fn generator() -> Self {
Affine::generator().into()
}

#[inline]
fn mul_bigint(&self, other: impl AsRef<[u64]>) -> Self {
Expand Down
Loading

0 comments on commit ab13aa0

Please sign in to comment.