::ScalarField,
>;
}
diff --git a/ec/src/models/bls12/g2.rs b/ec/src/models/bls12/g2.rs
index 661486351..629ddcda4 100644
--- a/ec/src/models/bls12/g2.rs
+++ b/ec/src/models/bls12/g2.rs
@@ -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};
@@ -20,8 +20,8 @@ pub type G2Projective = Projective<
::G2Config>;
Eq(bound = "P: Bls12Config")
)]
pub struct G2Prepared {
- // Stores the coefficients of the line evaluations as calculated in
- // https://eprint.iacr.org/2013/722.pdf
+ /// Stores the coefficients of the line evaluations as calculated in
+ ///
pub ell_coeffs: Vec>,
pub infinity: bool,
}
@@ -57,7 +57,7 @@ impl From> for G2Prepared {
ell_coeffs: vec![],
infinity: true,
};
- q.xy().map_or(zero, |(&q_x, &q_y)| {
+ q.xy().map_or(zero, |(q_x, q_y)| {
let mut ell_coeffs = vec![];
let mut r = G2HomProjective::
{
x: q_x,
@@ -133,7 +133,7 @@ impl G2HomProjective {
}
fn add_in_place(&mut self, q: &G2Affine
) -> EllCoeff
{
- let (&qx, &qy) = q.xy().unwrap();
+ let (qx, qy) = q.xy().unwrap();
// Formula for line function when working with
// homogeneous projective coordinates.
let theta = self.y - &(qy * &self.z);
diff --git a/ec/src/models/bls12/mod.rs b/ec/src/models/bls12/mod.rs
index ca8a66351..f5275f697 100644
--- a/ec/src/models/bls12/mod.rs
+++ b/ec/src/models/bls12/mod.rs
@@ -178,13 +178,13 @@ impl Bls12 {
match P::TWIST_TYPE {
TwistType::M => {
- c2.mul_assign_by_fp(py);
- c1.mul_assign_by_fp(px);
+ c2.mul_assign_by_fp(&py);
+ c1.mul_assign_by_fp(&px);
f.mul_by_014(&c0, &c1, &c2);
},
TwistType::D => {
- c0.mul_assign_by_fp(py);
- c1.mul_assign_by_fp(px);
+ c0.mul_assign_by_fp(&py);
+ c1.mul_assign_by_fp(&px);
f.mul_by_034(&c0, &c1, &c2);
},
}
diff --git a/ec/src/models/bn/g2.rs b/ec/src/models/bn/g2.rs
index 231b74402..281064496 100644
--- a/ec/src/models/bn/g2.rs
+++ b/ec/src/models/bn/g2.rs
@@ -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;
@@ -21,8 +24,8 @@ pub type G2Projective
= Projective<
::G2Config>;
Eq(bound = "P: BnConfig")
)]
pub struct G2Prepared {
- // Stores the coefficients of the line evaluations as calculated in
- // https://eprint.iacr.org/2013/722.pdf
+ /// Stores the coefficients of the line evaluations as calculated in
+ ///
pub ell_coeffs: Vec>,
pub infinity: bool,
}
diff --git a/ec/src/models/bw6/g2.rs b/ec/src/models/bw6/g2.rs
index 02430bead..7614e2c5b 100644
--- a/ec/src/models/bw6/g2.rs
+++ b/ec/src/models/bw6/g2.rs
@@ -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;
@@ -21,8 +21,8 @@ pub type G2Projective = Projective<
::G2Config>;
Eq(bound = "P: BW6Config")
)]
pub struct G2Prepared {
- // Stores the coefficients of the line evaluations as calculated in
- // https://eprint.iacr.org/2013/722.pdf
+ /// Stores the coefficients of the line evaluations as calculated in
+ ///
pub ell_coeffs_1: Vec<(P::Fp, P::Fp, P::Fp)>,
pub ell_coeffs_2: Vec<(P::Fp, P::Fp, P::Fp)>,
pub infinity: bool,
@@ -127,7 +127,8 @@ impl G2Prepared {
impl G2HomProjective {
fn double_in_place(&mut self) -> (P::Fp, P::Fp, P::Fp) {
// Formula for line function when working with
- // homogeneous projective coordinates, as described in https://eprint.iacr.org/2013/722.pdf.
+ // homogeneous projective coordinates, as described in
+ // .
let a = self.x * &self.y;
let b = self.y.square();
diff --git a/ec/src/models/mnt4/mod.rs b/ec/src/models/mnt4/mod.rs
index dc292ba73..c9a618c9c 100644
--- a/ec/src/models/mnt4/mod.rs
+++ b/ec/src/models/mnt4/mod.rs
@@ -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};
@@ -60,7 +60,7 @@ pub trait MNT4Config: 'static + Sized {
fn final_exponentiation(f: MillerLoopOutput>) -> Option>> {
let value = f.0;
- let value_inv = value.inverse().unwrap();
+ let value_inv = value.inverse()?;
let value_to_first_chunk =
MNT4::::final_exponentiation_first_chunk(&value, &value_inv);
let value_inv_to_first_chunk =
diff --git a/ec/src/models/mnt6/g2.rs b/ec/src/models/mnt6/g2.rs
index 0a79a270a..cf2639c90 100644
--- a/ec/src/models/mnt6/g2.rs
+++ b/ec/src/models/mnt6/g2.rs
@@ -1,5 +1,3 @@
-use core::ops::Neg;
-
use crate::{
mnt6::MNT6Config,
models::mnt6::MNT6,
@@ -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 = Affine<
::G2Config>;
diff --git a/ec/src/models/mnt6/mod.rs b/ec/src/models/mnt6/mod.rs
index 53d4f2ca8..47b0f70c5 100644
--- a/ec/src/models/mnt6/mod.rs
+++ b/ec/src/models/mnt6/mod.rs
@@ -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};
@@ -61,7 +61,7 @@ pub trait MNT6Config: 'static + Sized {
fn final_exponentiation(f: MillerLoopOutput>) -> Option>> {
let value = f.0;
- let value_inv = value.inverse().unwrap();
+ let value_inv = value.inverse()?;
let value_to_first_chunk =
MNT6::::final_exponentiation_first_chunk(&value, &value_inv);
let value_inv_to_first_chunk =
diff --git a/ec/src/models/short_weierstrass/affine.rs b/ec/src/models/short_weierstrass/affine.rs
index b1340de3a..1d1d9a04d 100644
--- a/ec/src/models/short_weierstrass/affine.rs
+++ b/ec/src/models/short_weierstrass/affine.rs
@@ -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;
@@ -205,8 +205,8 @@ impl AffineRepr for Affine {
type ScalarField = P::ScalarField;
type Group = Projective
;
- fn xy(&self) -> Option<(&Self::BaseField, &Self::BaseField)> {
- (!self.infinity).then(|| (&self.x, &self.y))
+ fn xy(&self) -> Option<(Self::BaseField, Self::BaseField)> {
+ (!self.infinity).then(|| (self.x, self.y))
}
#[inline]
diff --git a/ec/src/models/short_weierstrass/group.rs b/ec/src/models/short_weierstrass/group.rs
index ad043f892..58e5026f7 100644
--- a/ec/src/models/short_weierstrass/group.rs
+++ b/ec/src/models/short_weierstrass/group.rs
@@ -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;
@@ -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
@@ -160,13 +160,11 @@ impl Zero for Projective {
}
}
-impl Group for Projective {
- type ScalarField = P::ScalarField;
+impl AdditiveGroup for Projective {
+ 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
@@ -273,6 +271,15 @@ impl Group for Projective {
self
}
}
+}
+
+impl PrimeGroup for Projective {
+ type ScalarField = P::ScalarField;
+
+ #[inline]
+ fn generator() -> Self {
+ Affine::generator().into()
+ }
#[inline]
fn mul_bigint(&self, other: impl AsRef<[u64]>) -> Self {
@@ -330,10 +337,10 @@ impl Neg for Projective {
}
impl>> AddAssign for Projective {
- /// Using http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
+ /// Using
fn add_assign(&mut self, other: T) {
let other = other.borrow();
- if let Some((&other_x, &other_y)) = other.xy() {
+ if let Some((other_x, other_y)) = other.xy() {
if self.is_zero() {
self.x = other_x;
self.y = other_y;
@@ -564,7 +571,7 @@ impl> Mul for Projective {
impl From> for Projective {
#[inline]
fn from(p: Affine
) -> Projective
{
- p.xy().map_or(Projective::zero(), |(&x, &y)| Self {
+ p.xy().map_or(Projective::zero(), |(x, y)| Self {
x,
y,
z: P::BaseField::one(),
diff --git a/ec/src/models/short_weierstrass/mod.rs b/ec/src/models/short_weierstrass/mod.rs
index 965cbb83f..20bf7029c 100644
--- a/ec/src/models/short_weierstrass/mod.rs
+++ b/ec/src/models/short_weierstrass/mod.rs
@@ -4,10 +4,14 @@ use ark_serialize::{
};
use ark_std::io::{Read, Write};
-use ark_ff::fields::Field;
-
-use crate::{scalar_mul::variable_base::VariableBaseMSM, AffineRepr, Group};
+use ark_ff::{fields::Field, AdditiveGroup};
+use crate::{
+ scalar_mul::{
+ sw_double_and_add_affine, sw_double_and_add_projective, variable_base::VariableBaseMSM,
+ },
+ AffineRepr,
+};
use num_traits::Zero;
mod affine;
@@ -61,7 +65,7 @@ pub trait SWCurveConfig: super::CurveConfig {
/// Check if the provided curve point is in the prime-order subgroup.
///
/// The default implementation multiplies `item` by the order `r` of the
- /// prime-order subgroup, and checks if the result is one.
+ /// prime-order subgroup, and checks if the result is zero.
/// Implementors can choose to override this default impl
/// if the given curve has faster methods
/// for performing this check (for example, via leveraging curve
@@ -80,29 +84,13 @@ pub trait SWCurveConfig: super::CurveConfig {
/// Default implementation of group multiplication for projective
/// coordinates
fn mul_projective(base: &Projective, scalar: &[u64]) -> Projective {
- let mut res = Projective::::zero();
- for b in ark_ff::BitIteratorBE::without_leading_zeros(scalar) {
- res.double_in_place();
- if b {
- res += base;
- }
- }
-
- res
+ sw_double_and_add_projective(base, scalar)
}
/// Default implementation of group multiplication for affine
/// coordinates.
fn mul_affine(base: &Affine, scalar: &[u64]) -> Projective {
- let mut res = Projective::::zero();
- for b in ark_ff::BitIteratorBE::without_leading_zeros(scalar) {
- res.double_in_place();
- if b {
- res += base
- }
- }
-
- res
+ sw_double_and_add_affine(base, scalar)
}
/// Default implementation for multi scalar multiplication
diff --git a/ec/src/models/short_weierstrass/serialization_flags.rs b/ec/src/models/short_weierstrass/serialization_flags.rs
index 13eb1c8de..c2c9c0b41 100644
--- a/ec/src/models/short_weierstrass/serialization_flags.rs
+++ b/ec/src/models/short_weierstrass/serialization_flags.rs
@@ -5,11 +5,11 @@ use ark_serialize::Flags;
/// The default flags (empty) should not change the binary representation.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum SWFlags {
- /// Represents a point with positive y-coordinate by setting the MSB to 1.
+ /// Represents a point with positive y-coordinate by setting all bits to 0.
YIsPositive = 0,
/// Represents the point at infinity by setting the setting the last-but-one bit to 1.
PointAtInfinity = 1 << 6,
- /// Represents a point with negative y-coordinate by setting all bits to 0.
+ /// Represents a point with negative y-coordinate by setting the MSB to 1.
YIsNegative = 1 << 7,
}
diff --git a/ec/src/models/twisted_edwards/affine.rs b/ec/src/models/twisted_edwards/affine.rs
index a6c908e31..2b168a809 100644
--- a/ec/src/models/twisted_edwards/affine.rs
+++ b/ec/src/models/twisted_edwards/affine.rs
@@ -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;
@@ -166,8 +166,8 @@ impl AffineRepr for Affine {
type ScalarField = P::ScalarField;
type Group = Projective
;
- fn xy(&self) -> Option<(&Self::BaseField, &Self::BaseField)> {
- (!self.is_zero()).then(|| (&self.x, &self.y))
+ fn xy(&self) -> Option<(Self::BaseField, Self::BaseField)> {
+ (!self.is_zero()).then(|| (self.x, self.y))
}
fn generator() -> Self {
diff --git a/ec/src/models/twisted_edwards/group.rs b/ec/src/models/twisted_edwards/group.rs
index d82d70a2e..88bf8128c 100644
--- a/ec/src/models/twisted_edwards/group.rs
+++ b/ec/src/models/twisted_edwards/group.rs
@@ -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;
@@ -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
@@ -150,12 +150,15 @@ impl Zero for Projective {
}
}
-impl Group for Projective {
- type ScalarField = P::ScalarField;
+impl AdditiveGroup for Projective {
+ 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"
@@ -190,6 +193,14 @@ impl Group for Projective {
self
}
+}
+
+impl PrimeGroup for Projective {
+ type ScalarField = P::ScalarField;
+
+ fn generator() -> Self {
+ Affine::generator().into()
+ }
#[inline]
fn mul_bigint(&self, other: impl AsRef<[u64]>) -> Self {
diff --git a/ec/src/models/twisted_edwards/mod.rs b/ec/src/models/twisted_edwards/mod.rs
index 67402ed69..6d326b3a2 100644
--- a/ec/src/models/twisted_edwards/mod.rs
+++ b/ec/src/models/twisted_edwards/mod.rs
@@ -4,10 +4,10 @@ use ark_serialize::{
};
use ark_std::io::{Read, Write};
-use crate::{scalar_mul::variable_base::VariableBaseMSM, AffineRepr, Group};
+use crate::{scalar_mul::variable_base::VariableBaseMSM, AffineRepr};
use num_traits::Zero;
-use ark_ff::fields::Field;
+use ark_ff::{fields::Field, AdditiveGroup};
mod affine;
pub use affine::*;
diff --git a/ec/src/pairing.rs b/ec/src/pairing.rs
index 05071a593..90012301e 100644
--- a/ec/src/pairing.rs
+++ b/ec/src/pairing.rs
@@ -1,4 +1,4 @@
-use ark_ff::{CyclotomicMultSubgroup, Field, One, PrimeField};
+use ark_ff::{AdditiveGroup, CyclotomicMultSubgroup, Field, One, PrimeField};
use ark_serialize::{
CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError, Valid, Validate,
};
@@ -16,7 +16,7 @@ use ark_std::{
};
use zeroize::Zeroize;
-use crate::{AffineRepr, CurveGroup, Group, VariableBaseMSM};
+use crate::{AffineRepr, CurveGroup, PrimeGroup, VariableBaseMSM};
/// Collection of types (mainly fields and curves) that together describe
/// how to compute a pairing over a pairing-friendly curve.
@@ -265,7 +265,18 @@ impl Distribution> for Standard {
}
}
-impl Group for PairingOutput {
+impl AdditiveGroup for PairingOutput {
+ type Scalar = P::ScalarField;
+
+ const ZERO: Self = Self(P::TargetField::ONE);
+
+ fn double_in_place(&mut self) -> &mut Self {
+ self.0.cyclotomic_square_in_place();
+ self
+ }
+}
+
+impl PrimeGroup for PairingOutput {
type ScalarField = P::ScalarField;
fn generator() -> Self {
@@ -277,11 +288,6 @@ impl Group for PairingOutput {
P::pairing(g1.into(), g2.into())
}
- fn double_in_place(&mut self) -> &mut Self {
- self.0.cyclotomic_square_in_place();
- self
- }
-
fn mul_bigint(&self, other: impl AsRef<[u64]>) -> Self {
Self(self.0.cyclotomic_exp(other.as_ref()))
}
diff --git a/ec/src/scalar_mul/glv.rs b/ec/src/scalar_mul/glv.rs
index 87f86176a..21ef70077 100644
--- a/ec/src/scalar_mul/glv.rs
+++ b/ec/src/scalar_mul/glv.rs
@@ -1,62 +1,148 @@
-use crate::{CurveConfig, CurveGroup};
+use crate::AdditiveGroup;
+use crate::{
+ short_weierstrass::{Affine, Projective, SWCurveConfig},
+ CurveGroup,
+};
+use ark_ff::{PrimeField, Zero};
+use num_bigint::{BigInt, BigUint, Sign};
+use num_traits::Signed;
/// The GLV parameters for computing the endomorphism and scalar decomposition.
-pub trait GLVConfig: Send + Sync + 'static + CurveConfig {
- /// A representation of curve points that enables efficient arithmetic by
- /// avoiding inversions.
- type Curve: CurveGroup;
-
- // Constants that are used to calculate `phi(G) := lambda*G`.
-
- /// Coefficient `a_1` of `f(y) = a_1 * (y + a_2) * (y + a_3)`.
- const COEFF_A1: Self::BaseField;
- /// Coefficient `a_2` of `f(y) = a_1 * (y + a_2) * (y + a_3)`.
- const COEFF_A2: Self::BaseField;
- /// Coefficient `a_3` of `f(y) = a_1 * (y + a_2) * (y + a_3)`.
- const COEFF_A3: Self::BaseField;
-
- /// Coefficient `b_1` of `g(y) = b_1 * (y + b_2) * (y + b_3)`.
- const COEFF_B1: Self::BaseField;
- /// Coefficient `b_2` of `g(y) = b_1 * (y + b_2) * (y + b_3)`.
- const COEFF_B2: Self::BaseField;
- /// Coefficient `b_3` of `g(y) = b_1 * (y + b_2) * (y + b_3)`.
- const COEFF_B3: Self::BaseField;
-
- /// Coefficient `c_1` of `h(y) = (y + c_1) * (y + c_2)`.
- const COEFF_C1: Self::BaseField;
- /// Coefficient `c_2` of `h(y) = (y + c_1) * (y + c_2)`.
- const COEFF_C2: Self::BaseField;
-
- // Constants for scalar decomposition.
- // This is a 2x2 matrix, which is practically the LLL-reduced bases.
-
- /// The first element of the matrix for scalar decomposition.
- const COEFF_N11: Self::ScalarField;
- /// The second element of the matrix for scalar decomposition.
- const COEFF_N12: Self::ScalarField;
- /// The third element of the matrix for scalar decomposition.
- const COEFF_N21: Self::ScalarField;
- /// The forth element of the matrix for the scalar decomposition.
- const COEFF_N22: Self::ScalarField;
-
- /// Maps a point G to phi(G):= lambda G where psi is the endomorphism.
- // On an affine curve, the function takes the following steps:
- // f(y) = a_1 * (y + a_2) * (y + a_3)
- // g(y) = b_1 * (y + b_2) * (y + b_3)
- // h(y) = (y + c_1) * (y + c_2)
- // return (x',y') where
- // x' = x * f(y) / y
- // y' = g(y) / h(y)
- fn endomorphism(
- base: &::Affine,
- ) -> ::Affine;
+pub trait GLVConfig: Send + Sync + 'static + SWCurveConfig {
+ /// Constants that are used to calculate `phi(G) := lambda*G`.
+
+ /// The coefficients of the endomorphism
+ const ENDO_COEFFS: &'static [Self::BaseField];
+
+ /// The eigenvalue corresponding to the endomorphism.
+ const LAMBDA: Self::ScalarField;
+
+ /// A 4-element vector representing a 2x2 matrix of coefficients the for scalar decomposition, s.t. k-th entry in the vector is at col i, row j in the matrix, with ij = BE binary decomposition of k.
+ /// The entries are the LLL-reduced bases.
+ /// The determinant of this matrix must equal `ScalarField::characteristic()`.
+ const SCALAR_DECOMP_COEFFS: [(bool, ::BigInt); 4];
/// Decomposes a scalar s into k1, k2, s.t. s = k1 + lambda k2,
- fn scalar_decomposition(k: &Self::ScalarField) -> (Self::ScalarField, Self::ScalarField);
+ fn scalar_decomposition(
+ k: Self::ScalarField,
+ ) -> ((bool, Self::ScalarField), (bool, Self::ScalarField)) {
+ let scalar: BigInt = k.into_bigint().into().into();
+
+ let coeff_bigints: [BigInt; 4] = Self::SCALAR_DECOMP_COEFFS.map(|x| {
+ BigInt::from_biguint(x.0.then_some(Sign::Plus).unwrap_or(Sign::Minus), x.1.into())
+ });
+
+ let [n11, n12, n21, n22] = coeff_bigints;
+
+ let r = BigInt::from(Self::ScalarField::MODULUS.into());
+
+ // beta = vector([k,0]) * self.curve.N_inv
+ // The inverse of N is 1/r * Matrix([[n22, -n12], [-n21, n11]]).
+ // so β = (k*n22, -k*n12)/r
+
+ let beta_1 = &scalar * &n22 / &r;
+ let beta_2 = &scalar * &n12 / &r;
+
+ // b = vector([int(beta[0]), int(beta[1])]) * self.curve.N
+ // b = (β1N11 + β2N21, β1N12 + β2N22) with the signs!
+ // = (b11 + b12 , b21 + b22) with the signs!
+
+ // b1
+ let b11 = &beta_1 * &n11;
+ let b12 = &beta_2 * &n21;
+ let b1 = b11 + b12;
+
+ // b2
+ let b21 = &beta_1 * &n12;
+ let b22 = &beta_2 * &n22;
+ let b2 = b21 + b22;
+
+ let k1 = &scalar - b1;
+ let k1_abs = BigUint::try_from(k1.abs()).unwrap();
+
+ // k2
+ let k2 = -b2;
+ let k2_abs = BigUint::try_from(k2.abs()).unwrap();
+
+ (
+ (k1.sign() == Sign::Plus, Self::ScalarField::from(k1_abs)),
+ (k2.sign() == Sign::Plus, Self::ScalarField::from(k2_abs)),
+ )
+ }
+
+ fn endomorphism(p: &Projective) -> Projective;
+
+ fn endomorphism_affine(p: &Affine) -> Affine;
+
+ fn glv_mul_projective(p: Projective, k: Self::ScalarField) -> Projective {
+ let ((sgn_k1, k1), (sgn_k2, k2)) = Self::scalar_decomposition(k);
+
+ let mut b1 = p;
+ let mut b2 = Self::endomorphism(&p);
+
+ if !sgn_k1 {
+ b1 = -b1;
+ }
+ if !sgn_k2 {
+ b2 = -b2;
+ }
+
+ let b1b2 = b1 + b2;
+
+ let iter_k1 = ark_ff::BitIteratorBE::new(k1.into_bigint());
+ let iter_k2 = ark_ff::BitIteratorBE::new(k2.into_bigint());
+
+ let mut res = Projective::::zero();
+ let mut skip_zeros = true;
+ for pair in iter_k1.zip(iter_k2) {
+ if skip_zeros && pair == (false, false) {
+ skip_zeros = false;
+ continue;
+ }
+ res.double_in_place();
+ match pair {
+ (true, false) => res += b1,
+ (false, true) => res += b2,
+ (true, true) => res += b1b2,
+ (false, false) => {},
+ }
+ }
+ res
+ }
+
+ fn glv_mul_affine(p: Affine, k: Self::ScalarField) -> Affine {
+ let ((sgn_k1, k1), (sgn_k2, k2)) = Self::scalar_decomposition(k);
+
+ let mut b1 = p;
+ let mut b2 = Self::endomorphism_affine(&p);
+
+ if !sgn_k1 {
+ b1 = -b1;
+ }
+ if !sgn_k2 {
+ b2 = -b2;
+ }
+
+ let b1b2 = b1 + b2;
+
+ let iter_k1 = ark_ff::BitIteratorBE::new(k1.into_bigint());
+ let iter_k2 = ark_ff::BitIteratorBE::new(k2.into_bigint());
- /// Performs GLV multiplication.
- fn glv_mul(
- base: &::Affine,
- scalar: &Self::ScalarField,
- ) -> Self::Curve;
+ let mut res = Projective::::zero();
+ let mut skip_zeros = true;
+ for pair in iter_k1.zip(iter_k2) {
+ if skip_zeros && pair == (false, false) {
+ skip_zeros = false;
+ continue;
+ }
+ res.double_in_place();
+ match pair {
+ (true, false) => res += b1,
+ (false, true) => res += b2,
+ (true, true) => res += b1b2,
+ (false, false) => {},
+ }
+ }
+ res.into_affine()
+ }
}
diff --git a/ec/src/scalar_mul/mod.rs b/ec/src/scalar_mul/mod.rs
index 9f81b75c7..1ae3a1e99 100644
--- a/ec/src/scalar_mul/mod.rs
+++ b/ec/src/scalar_mul/mod.rs
@@ -4,7 +4,9 @@ pub mod wnaf;
pub mod fixed_base;
pub mod variable_base;
-use crate::Group;
+use crate::PrimeGroup;
+use crate::short_weierstrass::{Affine, Projective, SWCurveConfig};
+use ark_ff::{AdditiveGroup, Zero};
use ark_std::{
ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign},
vec::Vec,
@@ -19,8 +21,42 @@ fn ln_without_floats(a: usize) -> usize {
(ark_std::log2(a) * 69 / 100) as usize
}
+/// Standard double-and-add method for multiplication by a scalar.
+#[inline(always)]
+pub fn sw_double_and_add_affine(
+ base: &Affine,
+ scalar: impl AsRef<[u64]>,
+) -> Projective
{
+ let mut res = Projective::
::zero();
+ for b in ark_ff::BitIteratorBE::without_leading_zeros(scalar) {
+ res.double_in_place();
+ if b {
+ res += base
+ }
+ }
+
+ res
+}
+
+/// Standard double-and-add method for multiplication by a scalar.
+#[inline(always)]
+pub fn sw_double_and_add_projective(
+ base: &Projective,
+ scalar: impl AsRef<[u64]>,
+) -> Projective
{
+ let mut res = Projective::
::zero();
+ for b in ark_ff::BitIteratorBE::without_leading_zeros(scalar) {
+ res.double_in_place();
+ if b {
+ res += base
+ }
+ }
+
+ res
+}
+
pub trait ScalarMul:
- Group
+ PrimeGroup
+ Add
+ AddAssign
+ for<'a> Add<&'a Self::MulBase, Output = Self>
diff --git a/ec/src/scalar_mul/variable_base/mod.rs b/ec/src/scalar_mul/variable_base/mod.rs
index bc4719c8f..6e485c9a3 100644
--- a/ec/src/scalar_mul/variable_base/mod.rs
+++ b/ec/src/scalar_mul/variable_base/mod.rs
@@ -24,7 +24,7 @@ pub trait VariableBaseMSM: ScalarMul {
Self::msm_bigint(bases, &bigints)
}
- /// Performs multi-scalar multiplication, without checking that `bases.len() == scalars.len()`.
+ /// Performs multi-scalar multiplication.
///
/// # Warning
///
diff --git a/ec/src/scalar_mul/wnaf.rs b/ec/src/scalar_mul/wnaf.rs
index d3e0b5437..0003538c5 100644
--- a/ec/src/scalar_mul/wnaf.rs
+++ b/ec/src/scalar_mul/wnaf.rs
@@ -1,4 +1,4 @@
-use crate::Group;
+use crate::PrimeGroup;
use ark_ff::{BigInteger, PrimeField};
use ark_std::vec::Vec;
@@ -20,7 +20,7 @@ impl WnafContext {
Self { window_size }
}
- pub fn table(&self, mut base: G) -> Vec {
+ pub fn table(&self, mut base: G) -> Vec {
let mut table = Vec::with_capacity(1 << (self.window_size - 1));
let dbl = base.double();
@@ -37,7 +37,7 @@ impl WnafContext {
/// multiplication; first, it uses `Self::table` to calculate an
/// appropriate table of multiples of `g`, and then uses the wNAF
/// algorithm to compute the scalar multiple.
- pub fn mul(&self, g: G, scalar: &G::ScalarField) -> G {
+ pub fn mul(&self, g: G, scalar: &G::ScalarField) -> G {
let table = self.table(g);
self.mul_with_table(&table, scalar).unwrap()
}
@@ -48,7 +48,11 @@ impl WnafContext {
/// `G::ScalarField`.
///
/// Returns `None` if the table is too small.
- pub fn mul_with_table(&self, base_table: &[G], scalar: &G::ScalarField) -> Option {
+ pub fn mul_with_table(
+ &self,
+ base_table: &[G],
+ scalar: &G::ScalarField,
+ ) -> Option {
if 1 << (self.window_size - 1) > base_table.len() {
return None;
}
diff --git a/ff-asm/Cargo.toml b/ff-asm/Cargo.toml
index 980020941..4e2680073 100644
--- a/ff-asm/Cargo.toml
+++ b/ff-asm/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "ark-ff-asm"
-version = "0.4.0"
+version = "0.4.2"
authors = [ "arkworks contributors" ]
description = "A library for generating x86-64 assembly for finite field multiplication"
homepage = "https://arkworks.rs"
diff --git a/ff-macros/Cargo.toml b/ff-macros/Cargo.toml
index ca96782ff..2bd7dd464 100644
--- a/ff-macros/Cargo.toml
+++ b/ff-macros/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "ark-ff-macros"
-version = "0.4.0"
+version = "0.4.2"
authors = [ "arkworks contributors" ]
description = "A library for generating x86-64 assembly for finite field multiplication"
homepage = "https://arkworks.rs"
diff --git a/ff-macros/src/lib.rs b/ff-macros/src/lib.rs
index d642d1a79..9d90d5840 100644
--- a/ff-macros/src/lib.rs
+++ b/ff-macros/src/lib.rs
@@ -131,6 +131,47 @@ fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option {
#[test]
fn test_str_to_limbs() {
+ use num_bigint::Sign::*;
+ for i in 0..100 {
+ for sign in [Plus, Minus] {
+ let number = 1i128 << i;
+ let signed_number = match sign {
+ Minus => -number,
+ Plus | _ => number,
+ };
+ for base in [2, 8, 16, 10] {
+ let mut string = match base {
+ 2 => format!("{:#b}", number),
+ 8 => format!("{:#o}", number),
+ 16 => format!("{:#x}", number),
+ 10 => format!("{}", number),
+ _ => unreachable!(),
+ };
+ if sign == Minus {
+ string.insert(0, '-');
+ }
+ let (is_positive, limbs) = utils::str_to_limbs(&format!("{}", string));
+ assert_eq!(
+ limbs[0],
+ format!("{}u64", signed_number.abs() as u64),
+ "{signed_number}, {i}"
+ );
+ if i > 63 {
+ assert_eq!(
+ limbs[1],
+ format!("{}u64", (signed_number.abs() >> 64) as u64),
+ "{signed_number}, {i}"
+ );
+ }
+
+ assert_eq!(is_positive, sign == Plus);
+ }
+ }
+ }
+ let (is_positive, limbs) = utils::str_to_limbs("0");
+ assert!(is_positive);
+ assert_eq!(&limbs, &["0u64".to_string()]);
+
let (is_positive, limbs) = utils::str_to_limbs("-5");
assert!(!is_positive);
assert_eq!(&limbs, &["5u64".to_string()]);
diff --git a/ff-macros/src/utils.rs b/ff-macros/src/utils.rs
index dde73e1a9..055fbf79f 100644
--- a/ff-macros/src/utils.rs
+++ b/ff-macros/src/utils.rs
@@ -1,6 +1,7 @@
use std::str::FromStr;
use num_bigint::{BigInt, Sign};
+use num_traits::Num;
use proc_macro::TokenStream;
use syn::{Expr, Lit};
@@ -26,9 +27,25 @@ pub fn str_to_limbs(num: &str) -> (bool, Vec) {
}
pub fn str_to_limbs_u64(num: &str) -> (bool, Vec) {
- let (sign, digits) = BigInt::from_str(num)
- .expect("could not parse to bigint")
- .to_radix_le(16);
+ let is_negative = num.starts_with('-');
+ let num = if is_negative { &num[1..] } else { num };
+ let number = if num.starts_with("0x") || num.starts_with("0X") {
+ // We are in hexadecimal
+ BigInt::from_str_radix(&num[2..], 16)
+ } else if num.starts_with("0o") || num.starts_with("0O") {
+ // We are in octal
+ BigInt::from_str_radix(&num[2..], 8)
+ } else if num.starts_with("0b") || num.starts_with("0B") {
+ // We are in binary
+ BigInt::from_str_radix(&num[2..], 2)
+ } else {
+ // We are in decimal
+ BigInt::from_str(num)
+ }
+ .expect("could not parse to bigint");
+ let number = if is_negative { -number } else { number };
+ let (sign, digits) = number.to_radix_le(16);
+
let limbs = digits
.chunks(16)
.map(|chunk| {
diff --git a/ff/Cargo.toml b/ff/Cargo.toml
index 29e5bb7da..69eeeafdb 100644
--- a/ff/Cargo.toml
+++ b/ff/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "ark-ff"
-version = "0.4.0"
+version = "0.4.2"
authors = [ "arkworks contributors" ]
description = "A library for finite fields"
homepage = "https://arkworks.rs"
@@ -8,16 +8,16 @@ repository = "https://github.com/arkworks-rs/algebra"
documentation = "https://docs.rs/ark-ff/"
keywords = ["cryptography", "finite-fields" ]
categories = ["cryptography"]
-include = ["Cargo.toml", "build.rs", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
+include = ["Cargo.toml", "build.rs", "src", "doc", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
license = "MIT/Apache-2.0"
edition = "2021"
rust-version = "1.63"
[dependencies]
-ark-ff-asm = { version = "0.4.0", path = "../ff-asm" }
-ark-ff-macros = { version = "0.4.0", path = "../ff-macros" }
+ark-ff-asm = { version = "0.4.2", path = "../ff-asm" }
+ark-ff-macros = { version = "0.4.2", path = "../ff-macros" }
ark-std = { version = "0.4.0", default-features = false }
-ark-serialize = { version = "0.4.0", path = "../serialize", default-features = false }
+ark-serialize = { version = "0.4.2", path = "../serialize", default-features = false }
derivative = { version = "2", features = ["use_core"] }
num-traits = { version = "0.2", default-features = false }
paste = "1.0"
@@ -28,7 +28,7 @@ digest = { version = "0.10", default-features = false, features = ["alloc"] }
itertools = { version = "0.10", default-features = false }
[dev-dependencies]
-ark-test-curves = { version = "0.4.0", path = "../test-curves", default-features = false, features = [ "bls12_381_curve", "mnt6_753", "secp256k1"] }
+ark-test-curves = { version = "0.4.2", path = "../test-curves", default-features = false, features = [ "bls12_381_curve", "mnt6_753", "secp256k1"] }
blake2 = { version = "0.10", default-features = false }
sha3 = { version = "0.10", default-features = false }
sha2 = { version = "0.10", default-features = false }
diff --git a/ff/README.md b/ff/README.md
index ce246ca73..4d50a2af2 100644
--- a/ff/README.md
+++ b/ff/README.md
@@ -7,7 +7,7 @@
This crate defines Finite Field traits and useful abstraction models that follow these traits.
-Implementations of concrete finite fields for some popular elliptic curves can be found in [`arkworks-rs/curves`](https://github.com/arkworks-rs/curves/README.md) under `arkworks-rs/curves//src/fields/`.
+Implementations of concrete finite fields for some popular elliptic curves can be found in [`arkworks-rs/curves`](https://github.com/arkworks-rs/curves/blob/master/README.md) under `arkworks-rs/curves//src/fields/`.
This crate contains two types of traits:
@@ -16,6 +16,7 @@ This crate contains two types of traits:
The available field traits are:
+- [`AdditiveGroup`](/ff/src/lib.rs) - Interface for additive groups that have a "scalar multiplication" operation with respect to the `Scalar` associated type. This applies to to prime-order fields, field extensions, and elliptic-curve groups used in cryptography.
- [`Field`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L66) - Interface for a generic finite field.
- [`FftField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L419) - Exposes methods that allow for performing efficient FFTs on field elements.
- [`PrimeField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L523) - Field with a prime `p` number of elements, also referred to as `Fp`.
@@ -28,7 +29,7 @@ The models implemented are:
- [`Cubic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs)
- [`CubicExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L72) - Struct representing a cubic extension field, holds three base field elements
- [`CubicExtConfig`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Cubic Extension Field
-
+
The above two models serve as abstractions for constructing the extension fields `Fp^m` directly (i.e. `m` equal 2 or 3) or for creating extension towers to arrive at higher `m`. The latter is done by applying the extensions iteratively, e.g. cubic extension over a quadratic extension field.
- [`Fp2`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp2.rs#L103) - Quadratic extension directly on the prime field, i.e. `BaseField == BasePrimeField`
@@ -42,14 +43,48 @@ The above two models serve as abstractions for constructing the extension fields
There are two important traits when working with finite fields: [`Field`],
and [`PrimeField`]. Let's explore these via examples.
-### [`Field`]
+### [`AdditiveGroup`][additive_group]
-The [`Field`] trait provides a generic interface for any finite field.
-Types implementing [`Field`] support common field operations
-such as addition, subtraction, multiplication, and inverses.
+The [`AdditiveGroup`][additive_group] trait provides a generic interface for additive groups that have an associated scalar multiplication operations. Types implementing this trait support common group operations such as addition, subtraction, negation, as well as scalar multiplication by the [`Scalar`][group_scalar_type] associated type.
```rust
-use ark_ff::Field;
+use ark_ff::AdditiveGroup;
+// We'll use a field associated with the BLS12-381 pairing-friendly
+// group for this example.
+use ark_test_curves::bls12_381::Fq2 as F;
+// `ark-std` is a utility crate that enables `arkworks` libraries
+// to easily support `std` and `no_std` workloads, and also re-exports
+// useful crates that should be common across the entire ecosystem, such as `rand`.
+use ark_std::{One, UniformRand};
+
+let mut rng = ark_std::test_rng();
+// Let's sample uniformly random field elements:
+let a = F::rand(&mut rng);
+let b = F::rand(&mut rng);
+let c = ::Scalar::rand(&mut rng);
+
+// We can add...
+let c = a + b;
+// ... subtract ...
+let d = a - b;
+// ... double elements ...
+assert_eq!(c + d, a.double());
+// ... negate them ...
+assert_ne!(d, -d);
+
+// ... and multiply them by scalars:
+let e = d * c;
+```
+
+### [`Field`][field]
+
+The [`Field`][field] trait provides a generic interface for any finite field.
+Types implementing [`Field`][field] support common field operations
+such as addition, subtraction, multiplication, and inverses, and are required
+to be [`AdditiveGroup`][additive_group]s too.
+
+```rust
+use ark_ff::{AdditiveGroup, Field};
// We'll use a field associated with the BLS12-381 pairing-friendly
// group for this example.
use ark_test_curves::bls12_381::Fq2 as F;
@@ -63,6 +98,7 @@ let mut rng = ark_std::test_rng();
let a = F::rand(&mut rng);
let b = F::rand(&mut rng);
+// We can perform all the operations from the `AdditiveGroup` trait:
// We can add...
let c = a + b;
// ... subtract ...
@@ -107,10 +143,10 @@ if a.legendre().is_qr() {
}
```
-### [`PrimeField`]
+### [`PrimeField`][prime_field]
If the field is of prime order, then users can choose
-to implement the [`PrimeField`] trait for it. This provides access to the following
+to implement the [`PrimeField`][prime_field] trait for it. This provides access to the following
additional APIs:
```rust
@@ -133,3 +169,8 @@ assert_eq!(one, num_bigint::BigUint::one());
let n = F::from_le_bytes_mod_order(&modulus.to_bytes_le());
assert_eq!(n, F::zero());
```
+
+[additive_group]: https://docs.rs/ark-ff/latest/ark_ff/fields/trait.AdditiveGroup.html
+[group_scalar_type]: https://docs.rs/ark-ff/latest/ark_ff/fields/trait.AdditiveGroup.html#associatedtype.Scalar
+[field]: https://docs.rs/ark-ff/latest/ark_ff/fields/trait.Field.html
+[prime_field]: https://docs.rs/ark-ff/latest/ark_ff/fields/trait.PrimeField.html
diff --git a/ff/src/fields/field_hashers/expander/mod.rs b/ff/src/fields/field_hashers/expander/mod.rs
index 4f927aa82..8b1ef0a12 100644
--- a/ff/src/fields/field_hashers/expander/mod.rs
+++ b/ff/src/fields/field_hashers/expander/mod.rs
@@ -77,9 +77,9 @@ impl Expander for ExpanderXmd {
let dst_prime = self.construct_dst_prime();
let z_pad: Vec = vec![0; self.block_size];
- // // Represent `len_in_bytes` as a 2-byte array.
- // // As per I2OSP method outlined in https://tools.ietf.org/pdf/rfc8017.pdf,
- // // The program should abort if integer that we're trying to convert is too large.
+ // Represent `len_in_bytes` as a 2-byte array.
+ // As per I2OSP method outlined in https://tools.ietf.org/pdf/rfc8017.pdf,
+ // The program should abort if integer that we're trying to convert is too large.
assert!(n < (1 << 16), "Length should be smaller than 2^16");
let lib_str: [u8; 2] = (n as u16).to_be_bytes();
diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs
index 4463953dd..08e3ebc45 100644
--- a/ff/src/fields/mod.rs
+++ b/ff/src/fields/mod.rs
@@ -1,3 +1,5 @@
+use core::iter::Product;
+
use crate::UniformRand;
use ark_serialize::{
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
@@ -42,14 +44,78 @@ use ark_std::cmp::max;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
-/// The interface for a generic field.
+pub trait AdditiveGroup:
+ Eq
+ + 'static
+ + Sized
+ + CanonicalSerialize
+ + CanonicalDeserialize
+ + Copy
+ + Clone
+ + Default
+ + Send
+ + Sync
+ + Hash
+ + Debug
+ + Display
+ + UniformRand
+ + Zeroize
+ + Zero
+ + Neg