Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CyclotomicField to represent cyclotomic operations #446

Merged
merged 4 commits into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
- [\#408](https://github.com/arkworks-rs/algebra/pull/408) (`ark-ff`) Change the output of `Display` formatting for BigInt & Fp from hex to decimal.
- [\#412](https://github.com/arkworks-rs/algebra/pull/412) (`ark-poly`) Rename UV/MVPolynomial to DenseUV/MVPolynomial.
- [\#417](https://github.com/arkworks-rs/algebra/pull/417) (`ark-ff`) Remove `ToBytes` and `FromBytes`.
- [\#418](https://github.com/arkworks-rs/algebra/pull/418) (`ark-ff`) Add `sums_of_products` to `Field` and `Fp`
- [\#422](https://github.com/arkworks-rs/algebra/pull/422) (`ark-ff`) Remove `SquareRootField`, and move functionality to `Field`
- [\#425](https://github.com/arkworks-rs/algebra/pull/425) (`ark-ec`) Refactor `VariableBase` struct to `VariableBaseMSM` trait and implement it for `GroupProjective`.
- [\#438](https://github.com/arkworks-rs/algebra/pull/438) (`ark-ec`) Rename modules, structs, and traits related to `ec`.
Expand All @@ -46,13 +47,17 @@
- `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.
- [\#443](https://github.com/arkworks-rs/algebra/pull/443), [\#449](https://github.com/arkworks-rs/algebra/pull/449) (`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>`
- Bound `AffineCurve` by
- `Mul<ScalarField, Output = ProjectiveCurve>`
- `for<'a> Mul<&'a ScalarField, Output = ProjectiveCurve>`
- [\#446](https://github.com/arkworks-rs/algebra/pull/446) (`ark-ff`) Add `CyclotomicMultSubgroup` trait and impl for extension fields

### Features

Expand All @@ -66,7 +71,11 @@
- [\#386](https://github.com/arkworks-rs/algebra/pull/386) (`ark-ff-macros`, `ark-ff`) Add a macro to derive `MontConfig`.
- [\#396](https://github.com/arkworks-rs/algebra/pull/396) (`ark-ec`) Add a default `mul` function to `{TE,SW}CurveConfig` trait definition.
- [\#397](https://github.com/arkworks-rs/algebra/pull/397) (`ark-ec`) Add `HashMapPippenger` to variable-base MSM.
- [\#418](https://github.com/arkworks-rs/algebra/pull/418) (`ark-ff`) Add `sums_of_products` to `Field` and `Fp`
- [\#420](https://github.com/arkworks-rs/algebra/pull/420) (`ark-ec`) Add a `clear_cofactor` method to `AffineCurve`.
- [\#430](https://github.com/arkworks-rs/algebra/pull/430) (`ark-ec`) Add functionality for mapping a field element to a curve element for hash-to-curve.
- [\#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.
- [\#446](https://github.com/arkworks-rs/algebra/pull/446) (`ark-ff`) Add `CyclotomicMultSubgroup` trait and impl for extension fields

### Improvements

Expand Down Expand Up @@ -205,7 +214,7 @@ The main features of this release are:
- [\#207](https://github.com/arkworks-rs/algebra/pull/207) (`ark-ff`) Improve performance of extension fields when the non-residue is negative. (Improves fq2, fq12, and g2 speed on bls12 and bn curves.)
- [\#211](https://github.com/arkworks-rs/algebra/pull/211) (`ark-ec`) Improve performance of BLS12 final exponentiation.
- [\#214](https://github.com/arkworks-rs/algebra/pull/214) (`ark-poly`) Utilise a more efficient way of evaluating a polynomial at a single point.
- [\#242](https://github.com/arkworks-rs/algebra/pull/242), [\#244][https://github.com/arkworks-rs/algebra/pull/244] (`ark-poly`) Speedup the sequential radix-2 FFT significantly by making the method in which it accesses roots more cache-friendly.
- [\#242](https://github.com/arkworks-rs/algebra/pull/242), [\#244](https://github.com/arkworks-rs/algebra/pull/244) (`ark-poly`) Speedup the sequential radix-2 FFT significantly by making the method in which it accesses roots more cache-friendly.

### Bugfixes

Expand Down
13 changes: 8 additions & 5 deletions ec/src/models/bls12/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ use crate::{
models::{short_weierstrass::SWCurveConfig, CurveConfig},
AffineCurve, PairingEngine,
};
use ark_ff::fields::{
fp12_2over3over2::{Fp12, Fp12Config},
fp2::Fp2Config,
fp6_3over2::Fp6Config,
BitIteratorBE, Field, Fp2, PrimeField,
use ark_ff::{
fields::{
fp12_2over3over2::{Fp12, Fp12Config},
fp2::Fp2Config,
fp6_3over2::Fp6Config,
BitIteratorBE, Field, Fp2, PrimeField,
},
CyclotomicMultSubgroup,
};
use core::marker::PhantomData;
use num_traits::{One, Zero};
Expand Down
13 changes: 8 additions & 5 deletions ec/src/models/bn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ use crate::{
models::{short_weierstrass::SWCurveConfig, CurveConfig},
PairingEngine,
};
use ark_ff::fields::{
fp12_2over3over2::{Fp12, Fp12Config},
fp2::Fp2Config,
fp6_3over2::Fp6Config,
Field, Fp2, PrimeField,
use ark_ff::{
fields::{
fp12_2over3over2::{Fp12, Fp12Config},
fp2::Fp2Config,
fp6_3over2::Fp6Config,
Field, Fp2, PrimeField,
},
CyclotomicMultSubgroup,
};
use num_traits::One;

Expand Down
11 changes: 7 additions & 4 deletions ec/src/models/bw6/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ use crate::{
models::{short_weierstrass::SWCurveConfig, CurveConfig},
PairingEngine,
};
use ark_ff::fields::{
fp3::Fp3Config,
fp6_2over3::{Fp6, Fp6Config},
BitIteratorBE, Field, PrimeField,
use ark_ff::{
fields::{
fp3::Fp3Config,
fp6_2over3::{Fp6, Fp6Config},
BitIteratorBE, Field, PrimeField,
},
CyclotomicMultSubgroup,
};
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},
BitIteratorBE, Field, PrimeField,
BitIteratorBE, CyclotomicMultSubgroup, Field, PrimeField,
};
use num_traits::{One, Zero};

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},
BitIteratorBE, Field, PrimeField,
BitIteratorBE, CyclotomicMultSubgroup, Field, PrimeField,
};
use num_traits::{One, Zero};

Expand Down
10 changes: 5 additions & 5 deletions ff/src/biginteger/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub(crate) fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
}

/// Compute the NAF (non-adjacent form) of num
pub fn find_naf(num: &[u64]) -> Vec<i64> {
pub fn find_naf(num: &[u64]) -> Vec<i8> {
Pratyush marked this conversation as resolved.
Show resolved Hide resolved
let is_zero = |num: &[u64]| num.iter().all(|x| *x == 0u64);
let is_odd = |num: &[u64]| num[0] & 1 == 1;
let sub_noborrow = |num: &mut [u64], z: u64| {
Expand Down Expand Up @@ -118,9 +118,9 @@ pub fn find_naf(num: &[u64]) -> Vec<i64> {
let mut res = vec![];

while !is_zero(&num) {
let z: i64;
let z: i8;
if is_odd(&num) {
z = 2 - (num[0] % 4) as i64;
z = 2 - (num[0] % 4) as i8;
if z >= 0 {
sub_noborrow(&mut num, z as u64)
} else {
Expand All @@ -147,9 +147,9 @@ pub fn find_naf(num: &[u64]) -> Vec<i64> {
/// This can be rewritten as ...0 1 1 to avoid one doubling, at the cost that we are making an
/// exception of non-adjacence for the most significant bit.
///
/// Since this representation is no longer a strict NAF, we call it ``relaxed NAF''.
/// Since this representation is no longer a strict NAF, we call it "relaxed NAF".
///
pub fn find_relaxed_naf(num: &[u64]) -> Vec<i64> {
pub fn find_relaxed_naf(num: &[u64]) -> Vec<i8> {
let mut res = find_naf(num);

let len = res.len();
Expand Down
22 changes: 12 additions & 10 deletions ff/src/biginteger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,6 @@ impl<const N: usize> Default for BigInt<N> {
}
}

impl<const N: usize> BigInt<N> {
pub const fn new(value: [u64; N]) -> Self {
Self(value)
}

pub const fn zero() -> Self {
Self([0u64; N])
}
}

/// Construct a [`struct@BigInt<N>`] element from a literal string.
///
/// # Panics
Expand Down Expand Up @@ -96,6 +86,18 @@ macro_rules! const_modulo {
}

impl<const N: usize> BigInt<N> {
pub const fn new(value: [u64; N]) -> Self {
Self(value)
}

pub const fn zero() -> Self {
Self([0u64; N])
}

pub const fn one() -> Self {
BigInt!("1")
}

#[doc(hidden)]
pub const fn const_is_even(&self) -> bool {
self.0[0] % 2 == 0
Expand Down
124 changes: 124 additions & 0 deletions ff/src/fields/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,130 @@ pub trait Field:
}
}

/// Fields that have a cyclotomic multiplicative subgroup, and which can
/// leverage efficient inversion and squaring algorithms for elements in this subgroup.
/// If a field has multiplicative order p^d - 1, the cyclotomic subgroups refer to subgroups of order φ_n(p),
/// for any n < d, where φ_n is the [n-th cyclotomic polynomial](https://en.wikipedia.org/wiki/Cyclotomic_polynomial).
///
/// ## Note
///
/// Note that this trait is unrelated to the `Group` trait from the `ark_ec` crate. That trait
/// denotes an *additive* group, while this trait denotes a *multiplicative* group.
pub trait CyclotomicMultSubgroup: Field {
/// Is the inverse fast to compute? For example, in quadratic extensions, the inverse
/// can be computed at the cost of negating one coordinate, which is much faster than
/// standard inversion.
/// By default this is `false`, but should be set to `true` for quadratic extensions.
const INVERSE_IS_FAST: bool = false;

/// Compute a square in the cyclotomic subgroup. By default this is computed using [`Field::square`], but for
/// degree 12 extensions, this can be computed faster than normal squaring.
///
/// # Warning
///
/// This method should be invoked only when `self` is in the cyclotomic subgroup.
fn cyclotomic_square(&self) -> Self {
let mut result = *self;
*result.cyclotomic_square_in_place()
}

/// Square `self` in place. By default this is computed using
/// [`Field::square_in_place`], but for degree 12 extensions,
/// this can be computed faster than normal squaring.
///
/// # Warning
///
/// This method should be invoked only when `self` is in the cyclotomic subgroup.
fn cyclotomic_square_in_place(&mut self) -> &mut Self {
self.square_in_place()
}

/// Compute the inverse of `self`. See [`Self::INVERSE_IS_FAST`] for details.
/// Returns [`None`] if `self.is_zero()`, and [`Some`] otherwise.
///
/// # Warning
///
/// This method should be invoked only when `self` is in the cyclotomic subgroup.
fn cyclotomic_inverse(&self) -> Option<Self> {
let mut result = *self;
result.cyclotomic_inverse_in_place().copied()
}

/// Compute the inverse of `self`. See [`Self::INVERSE_IS_FAST`] for details.
/// Returns [`None`] if `self.is_zero()`, and [`Some`] otherwise.
///
/// # Warning
///
/// This method should be invoked only when `self` is in the cyclotomic subgroup.
fn cyclotomic_inverse_in_place(&mut self) -> Option<&mut Self> {
self.inverse_in_place()
}

/// Compute a cyclotomic exponentiation of `self` with respect to `e`.
///
/// # Warning
///
/// This method should be invoked only when `self` is in the cyclotomic subgroup.
fn cyclotomic_exp(&self, e: impl AsRef<[u64]>) -> Self {
let mut result = *self;
result.cyclotomic_exp_in_place(e);
result
}

/// Set `self` to be the result of exponentiating [`self`] by `e`,
/// using efficient cyclotomic algorithms.
///
/// # Warning
///
/// This method should be invoked only when `self` is in the cyclotomic subgroup.
fn cyclotomic_exp_in_place(&mut self, e: impl AsRef<[u64]>) {
if self.is_zero() {
return;
}

if Self::INVERSE_IS_FAST {
// We only use NAF-based exponentiation if inverses are fast to compute.
let naf = crate::biginteger::arithmetic::find_naf(e.as_ref());
exp_loop(self, naf.into_iter().rev())
} else {
exp_loop(
self,
BitIteratorBE::without_leading_zeros(e.as_ref()).map(|e| e as i8),
)
};
}
}

/// Helper function to calculate the double-and-add loop for exponentiation.
fn exp_loop<F: CyclotomicMultSubgroup, I: Iterator<Item = i8>>(f: &mut F, e: I) {
// If the inverse is fast and we're using naf, we compute the inverse of the base.
// Otherwise we do nothing with the variable, so we default it to one.
let self_inverse = if F::INVERSE_IS_FAST {
f.cyclotomic_inverse().unwrap() // The inverse must exist because self is not zero.
} else {
F::one()
};
let mut res = F::one();
let mut found_nonzero = false;
for value in e {
if found_nonzero {
res.cyclotomic_square_in_place();
}

if value != 0 {
found_nonzero = true;

if value > 0 {
res *= &*f;
} else if F::INVERSE_IS_FAST {
// only use naf if inversion is fast.
res *= &self_inverse;
}
}
}
*f = res;
}

/// The interface for fields that are able to be used in FFTs.
pub trait FftField: Field {
/// The generator of the multiplicative group of the field
Expand Down
Loading