Skip to content

Commit

Permalink
Improve ergonomics of scalar field multiplication. (#443)
Browse files Browse the repository at this point in the history
Co-authored-by: Michele Orrù <[email protected]>
Co-authored-by: George Kadianakis <[email protected]>
Co-authored-by: Pratyush Mishra <[email protected]>
Co-authored-by: Weikeng Chen <[email protected]>
  • Loading branch information
4 people authored Aug 1, 2022
1 parent ffea2b8 commit dd5b9d6
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 54 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
- `TEModelParameters``TECurveConfig`
- `MontgomeryModelParameters``MontCurveConfig`
- [\#440](https://github.com/arkworks-rs/algebra/pull/440) (`ark-ff`) Add a method to construct a field element from an element of the underlying base prime field.
- [\#443](https://github.com/arkworks-rs/algebra/pull/443) (`ark-ec`) Improve ergonomics of scalar multiplication.
- Rename `ProjectiveCurve::mul(AsRef[u64])` to `ProjectiveCurve::mul_bigint(AsRef[u64])`.
- Bound `ProjectiveCurve` by
- `Mul<ScalarField>`,
- `for<'a> Mul<&'a ScalarField>`
- `MulAssign<ScalarField>`,
- `for<'a> MulAssign<&'a ScalarField>`

### Features

Expand Down
12 changes: 8 additions & 4 deletions ec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{
fmt::{Debug, Display},
hash::Hash,
ops::{Add, AddAssign, MulAssign, Neg, Sub, SubAssign},
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
vec::Vec,
};
use msm::VariableBaseMSM;
Expand Down Expand Up @@ -149,13 +149,16 @@ pub trait ProjectiveCurve:
+ Neg<Output = Self>
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Mul<<Self as ProjectiveCurve>::ScalarField, Output = Self>
+ AddAssign<Self>
+ SubAssign<Self>
+ MulAssign<<Self as ProjectiveCurve>::ScalarField>
+ for<'a> Add<&'a Self, Output = Self>
+ for<'a> Sub<&'a Self, Output = Self>
+ for<'a> Mul<&'a <Self as ProjectiveCurve>::ScalarField, Output = Self>
+ for<'a> AddAssign<&'a Self>
+ for<'a> SubAssign<&'a Self>
+ for<'a> MulAssign<&'a <Self as ProjectiveCurve>::ScalarField>
+ core::iter::Sum<Self>
+ for<'a> core::iter::Sum<&'a Self>
+ From<<Self as ProjectiveCurve>::Affine>
Expand Down Expand Up @@ -220,7 +223,7 @@ pub trait ProjectiveCurve:
fn add_assign_mixed(&mut self, other: &Self::Affine);

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

/// Affine representation of an elliptic curve point guaranteed to be
Expand Down Expand Up @@ -285,7 +288,7 @@ pub trait AffineCurve:

/// Performs scalar multiplication of this element with mixed addition.
#[must_use]
fn mul<S: Into<<Self::ScalarField as PrimeField>::BigInt>>(&self, by: S) -> Self::Projective;
fn mul_bigint<S: AsRef<[u64]>>(&self, by: S) -> Self::Projective;

/// Performs cofactor clearing.
/// The default method is simply to multiply by the cofactor.
Expand All @@ -308,7 +311,8 @@ pub trait AffineCurve:
/// `Self::ScalarField`.
#[must_use]
fn mul_by_cofactor_inv(&self) -> Self {
self.mul(Self::Config::COFACTOR_INV).into()
self.mul_bigint(&Self::Config::COFACTOR_INV.into_bigint())
.into()
}
}

Expand Down
30 changes: 19 additions & 11 deletions ec/src/models/short_weierstrass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@ use ark_serialize::{
CanonicalSerializeWithFlags, SWFlags, SerializationError,
};
use ark_std::{
borrow::Borrow,
fmt::{Display, Formatter, Result as FmtResult},
hash::{Hash, Hasher},
io::{Read, Write},
ops::{Add, AddAssign, MulAssign, Neg, Sub, SubAssign},
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
vec::Vec,
};

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

use crate::{msm::VariableBaseMSM, AffineCurve, ProjectiveCurve};

Expand Down Expand Up @@ -326,8 +324,8 @@ impl<P: SWCurveConfig> AffineCurve for Affine<P> {
})
}

fn mul<S: Into<<Self::ScalarField as PrimeField>::BigInt>>(&self, by: S) -> Self::Projective {
P::mul_affine(self, by.into().as_ref())
fn mul_bigint<S: AsRef<[u64]>>(&self, by: S) -> Self::Projective {
P::mul_affine(self, by.as_ref())
}

/// Multiplies this element by the cofactor and output the
Expand Down Expand Up @@ -688,7 +686,7 @@ impl<P: SWCurveConfig> ProjectiveCurve for Projective<P> {
}

#[inline]
fn mul<S: AsRef<[u64]>>(self, other: S) -> Self {
fn mul_bigint<S: AsRef<[u64]>>(self, other: S) -> Self {
P::mul_projective(&self, other.as_ref())
}
}
Expand Down Expand Up @@ -796,9 +794,19 @@ impl<'a, P: SWCurveConfig> SubAssign<&'a Self> for Projective<P> {
}
}

impl<P: SWCurveConfig> MulAssign<P::ScalarField> for Projective<P> {
fn mul_assign(&mut self, other: P::ScalarField) {
*self = self.mul(other.into_bigint())
impl<P: SWCurveConfig, T: Borrow<P::ScalarField>> MulAssign<T> for Projective<P> {
fn mul_assign(&mut self, other: T) {
*self = self.mul_bigint(other.borrow().into_bigint())
}
}

impl<'a, P: SWCurveConfig, T: Borrow<P::ScalarField>> Mul<T> for Projective<P> {
type Output = Self;

#[inline]
fn mul(mut self, other: T) -> Self {
self *= other;
self
}
}

Expand Down
32 changes: 20 additions & 12 deletions ec/src/models/twisted_edwards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ use ark_serialize::{
CanonicalSerializeWithFlags, EdwardsFlags, SerializationError,
};
use ark_std::{
borrow::Borrow,
fmt::{Display, Formatter, Result as FmtResult},
hash::{Hash, Hasher},
io::{Read, Write},
ops::{Add, AddAssign, MulAssign, Neg, Sub, SubAssign},
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
rand::{
distributions::{Distribution, Standard},
Rng,
Expand All @@ -17,10 +18,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, PrimeField, ToConstraintField, UniformRand};

#[cfg(feature = "parallel")]
use rayon::prelude::*;
Expand Down Expand Up @@ -234,8 +232,8 @@ impl<P: TECurveConfig> AffineCurve for Affine<P> {
})
}

fn mul<S: Into<<Self::ScalarField as PrimeField>::BigInt>>(&self, by: S) -> Self::Projective {
P::mul_affine(self, by.into().as_ref())
fn mul_bigint<S: AsRef<[u64]>>(&self, by: S) -> Self::Projective {
P::mul_affine(self, by.as_ref())
}

/// Multiplies this element by the cofactor and output the
Expand Down Expand Up @@ -315,7 +313,7 @@ impl<'a, P: TECurveConfig> SubAssign<&'a Self> for Affine<P> {

impl<P: TECurveConfig> MulAssign<P::ScalarField> for Affine<P> {
fn mul_assign(&mut self, other: P::ScalarField) {
*self = self.mul(other.into_bigint()).into()
*self = self.mul_bigint(&other.into_bigint()).into()
}
}

Expand Down Expand Up @@ -573,7 +571,7 @@ impl<P: TECurveConfig> ProjectiveCurve for Projective<P> {
}

#[inline]
fn mul<S: AsRef<[u64]>>(self, other: S) -> Self {
fn mul_bigint<S: AsRef<[u64]>>(self, other: S) -> Self {
P::mul_projective(&self, other.as_ref())
}
}
Expand Down Expand Up @@ -655,9 +653,19 @@ impl<'a, P: TECurveConfig> SubAssign<&'a Self> for Projective<P> {
}
}

impl<P: TECurveConfig> MulAssign<P::ScalarField> for Projective<P> {
fn mul_assign(&mut self, other: P::ScalarField) {
*self = self.mul(other.into_bigint())
impl<P: TECurveConfig, T: Borrow<P::ScalarField>> MulAssign<T> for Projective<P> {
fn mul_assign(&mut self, other: T) {
*self = self.mul_bigint(other.borrow().into_bigint())
}
}

impl<P: TECurveConfig, T: Borrow<P::ScalarField>> Mul<T> for Projective<P> {
type Output = Self;

#[inline]
fn mul(mut self, other: T) -> Self {
self *= other;
self
}
}

Expand Down
4 changes: 2 additions & 2 deletions test-curves/src/bls12_381/g2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl short_weierstrass::SWCurveConfig for Parameters {
// Checks that [p]P = [X]P

let mut x_times_point =
point.mul(BigInt::new([crate::bls12_381::Parameters::X[0], 0, 0, 0]));
point.mul_bigint(BigInt::new([crate::bls12_381::Parameters::X[0], 0, 0, 0]));
if crate::bls12_381::Parameters::X_IS_NEGATIVE {
x_times_point = -x_times_point;
}
Expand Down Expand Up @@ -99,7 +99,7 @@ impl short_weierstrass::SWCurveConfig for Parameters {

// tmp2 = [x^2]P + [x]ψ(P)
let mut tmp2: Projective<Parameters> = tmp;
tmp2 = tmp2.mul(x).neg();
tmp2 = tmp2.mul_bigint(x).neg();

// add up all the terms
psi2_p2 += tmp2;
Expand Down
47 changes: 23 additions & 24 deletions test-templates/src/curves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,14 @@ fn random_multiplication_test<G: ProjectiveCurve>() {
tmp2.add_assign(&b);

// Affine multiplication
let mut tmp3 = a_affine.mul(s.into_bigint());
tmp3.add_assign(&b_affine.mul(s.into_bigint()));

let mut tmp3 = a_affine.mul_bigint(&s.into_bigint());
tmp3.add_assign(&b_affine.mul_bigint(&s.into_bigint()));
assert_eq!(tmp1, tmp2);
assert_eq!(tmp1, tmp3);

let expected = a_affine.mul_bigint(s.into_bigint());
let got = a_affine.mul_bigint(&s.into_bigint());
assert_eq!(expected, got);
}
}

Expand Down Expand Up @@ -304,12 +307,12 @@ pub fn curve_tests<G: ProjectiveCurve>() {

assert_eq!(zero, zero);
assert_eq!(zero.is_zero(), true);
assert_eq!(a.mul(&fr_one.into_bigint()), a);
assert_eq!(a.mul(&fr_two.into_bigint()), a + &a);
assert_eq!(a.mul(&fr_zero.into_bigint()), zero);
assert_eq!(a.mul(&fr_zero.into_bigint()) - &a, -a);
assert_eq!(a.mul(&fr_one.into_bigint()) - &a, zero);
assert_eq!(a.mul(&fr_two.into_bigint()) - &a, a);
assert_eq!(a.mul(&fr_one), a);
assert_eq!(a.mul(&fr_two), a + &a);
assert_eq!(a.mul(&fr_zero), zero);
assert_eq!(a.mul(&fr_zero) - &a, -a);
assert_eq!(a.mul(&fr_one) - &a, zero);
assert_eq!(a.mul(&fr_two) - &a, a);

// a == a
assert_eq!(a, a);
Expand Down Expand Up @@ -341,31 +344,27 @@ pub fn curve_tests<G: ProjectiveCurve>() {

let fr_rand1 = G::ScalarField::rand(&mut rng);
let fr_rand2 = G::ScalarField::rand(&mut rng);
let a_rand1 = a.mul(&fr_rand1.into_bigint());
let a_rand2 = a.mul(&fr_rand2.into_bigint());
let a_rand1 = a.mul(&fr_rand1);
let a_rand2 = a.mul(&fr_rand2);
let fr_three = fr_two + &fr_rand1;
let a_two = a.mul(&fr_two.into_bigint());
let a_two = a.mul(&fr_two);
assert_eq!(a_two, a.double(), "(a * 2) != a.double()");
let a_six = a.mul(&(fr_three * &fr_two).into_bigint());
assert_eq!(
a_two.mul(&fr_three.into_bigint()),
a_six,
"(a * 2) * 3 != a * (2 * 3)"
);
let a_six = a.mul(&(fr_three * &fr_two));
assert_eq!(a_two.mul(&fr_three), a_six, "(a * 2) * 3 != a * (2 * 3)");

assert_eq!(
a_rand1.mul(&fr_rand2.into_bigint()),
a_rand2.mul(&fr_rand1.into_bigint()),
a_rand1.mul(&fr_rand2),
a_rand2.mul(&fr_rand1),
"(a * r1) * r2 != (a * r2) * r1"
);
assert_eq!(
a_rand2.mul(&fr_rand1.into_bigint()),
a.mul(&(fr_rand1 * &fr_rand2).into_bigint()),
a_rand2.mul(&fr_rand1),
a.mul(&(fr_rand1 * &fr_rand2)),
"(a * r2) * r1 != a * (r1 * r2)"
);
assert_eq!(
a_rand1.mul(&fr_rand2.into_bigint()),
a.mul(&(fr_rand1 * &fr_rand2).into_bigint()),
a_rand1.mul(&fr_rand2),
a.mul(&(fr_rand1 * &fr_rand2)),
"(a * r1) * r2 != a * (r1 * r2)"
);
}
Expand Down
2 changes: 1 addition & 1 deletion test-templates/src/msm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn naive_var_base_msm<G: AffineCurve>(bases: &[G], scalars: &[G::ScalarField]) -
let mut acc = G::Projective::zero();

for (base, scalar) in bases.iter().zip(scalars.iter()) {
acc += &base.mul(scalar.into_bigint());
acc += base.mul_bigint(&scalar.into_bigint());
}
acc
}
Expand Down

0 comments on commit dd5b9d6

Please sign in to comment.