diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aa0352d4..001e7140a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,6 +130,10 @@ - Remove method `generator_inv`. - Remove method `divide_by_vanishing_poly_on_coset_in_place`. - Remove coset fft methods: `coset_fft`, `coset_fft_in_place`, `coset_ifft`, `coset_ifft_in_place`. +- [\#492](https://github.com/arkworks-rs/algebra/pull/492) (`ark-ff`) Refactor `ark-ff` APIs: + - Splits the contents of `ff/src/fields/mod.rs` into smaller files for easier management. + - Moves `BitIterator` out of `ark_ff::fields` and into `ark_ff` directly. + - Adds `impl<'a, 'b> Add/Sub/Mul/Div<&'a F> for &'b F` ### Features diff --git a/ec/src/models/bls12/g2.rs b/ec/src/models/bls12/g2.rs index 4016b5e4f..4dfefd4dc 100644 --- a/ec/src/models/bls12/g2.rs +++ b/ec/src/models/bls12/g2.rs @@ -1,4 +1,4 @@ -use ark_ff::fields::{BitIteratorBE, Field, Fp2}; +use ark_ff::{BitIteratorBE, Field, Fp2}; use ark_serialize::*; use ark_std::{vec::Vec, One}; diff --git a/ec/src/models/bls12/mod.rs b/ec/src/models/bls12/mod.rs index d14d28d87..b7bd03415 100644 --- a/ec/src/models/bls12/mod.rs +++ b/ec/src/models/bls12/mod.rs @@ -8,9 +8,9 @@ use ark_ff::{ fp12_2over3over2::{Fp12, Fp12Config}, fp2::Fp2Config, fp6_3over2::Fp6Config, - BitIteratorBE, Field, Fp2, PrimeField, + Fp2, }, - CyclotomicMultSubgroup, + BitIteratorBE, CyclotomicMultSubgroup, Field, PrimeField, }; use ark_std::{marker::PhantomData, vec::Vec}; use num_traits::{One, Zero}; diff --git a/ec/src/models/bw6/g2.rs b/ec/src/models/bw6/g2.rs index 333d20930..2196fd56b 100644 --- a/ec/src/models/bw6/g2.rs +++ b/ec/src/models/bw6/g2.rs @@ -1,4 +1,4 @@ -use ark_ff::fields::{BitIteratorBE, Field}; +use ark_ff::{BitIteratorBE, Field}; use ark_serialize::*; use ark_std::vec::Vec; use num_traits::One; diff --git a/ec/src/models/bw6/mod.rs b/ec/src/models/bw6/mod.rs index ea00be9bc..da628cd01 100644 --- a/ec/src/models/bw6/mod.rs +++ b/ec/src/models/bw6/mod.rs @@ -6,9 +6,9 @@ use ark_ff::{ fields::{ fp3::Fp3Config, fp6_2over3::{Fp6, Fp6Config}, - BitIteratorBE, Field, PrimeField, + Field, PrimeField, }, - CyclotomicMultSubgroup, + BitIteratorBE, CyclotomicMultSubgroup, }; use itertools::Itertools; use num_traits::One; diff --git a/ff/src/biginteger/mod.rs b/ff/src/biginteger/mod.rs index 35f1929cd..19aa582e2 100644 --- a/ff/src/biginteger/mod.rs +++ b/ff/src/biginteger/mod.rs @@ -1,7 +1,6 @@ use crate::{ - const_for, - fields::{BitIteratorBE, BitIteratorLE}, - UniformRand, + bits::{BitIteratorBE, BitIteratorLE}, + const_for, UniformRand, }; #[allow(unused)] use ark_ff_macros::unroll_for_loops; diff --git a/ff/src/bits.rs b/ff/src/bits.rs new file mode 100644 index 000000000..049aaa37d --- /dev/null +++ b/ff/src/bits.rs @@ -0,0 +1,82 @@ +/// Iterates over a slice of `u64` in *big-endian* order. +#[derive(Debug)] +pub struct BitIteratorBE> { + s: Slice, + n: usize, +} + +impl> BitIteratorBE { + pub fn new(s: Slice) -> Self { + let n = s.as_ref().len() * 64; + BitIteratorBE { s, n } + } + + /// Construct an iterator that automatically skips any leading zeros. + /// That is, it skips all zeros before the most-significant one. + pub fn without_leading_zeros(s: Slice) -> impl Iterator { + Self::new(s).skip_while(|b| !b) + } +} + +impl> Iterator for BitIteratorBE { + type Item = bool; + + fn next(&mut self) -> Option { + if self.n == 0 { + None + } else { + self.n -= 1; + let part = self.n / 64; + let bit = self.n - (64 * part); + + Some(self.s.as_ref()[part] & (1 << bit) > 0) + } + } +} + +/// Iterates over a slice of `u64` in *little-endian* order. +#[derive(Debug)] +pub struct BitIteratorLE> { + s: Slice, + n: usize, + max_len: usize, +} + +impl> BitIteratorLE { + pub fn new(s: Slice) -> Self { + let n = 0; + let max_len = s.as_ref().len() * 64; + BitIteratorLE { s, n, max_len } + } + + /// Construct an iterator that automatically skips any trailing zeros. + /// That is, it skips all zeros after the most-significant one. + pub fn without_trailing_zeros(s: Slice) -> impl Iterator { + let mut first_trailing_zero = 0; + for (i, limb) in s.as_ref().iter().enumerate().rev() { + first_trailing_zero = i * 64 + (64 - limb.leading_zeros()) as usize; + if *limb != 0 { + break; + } + } + let mut iter = Self::new(s); + iter.max_len = first_trailing_zero; + iter + } +} + +impl> Iterator for BitIteratorLE { + type Item = bool; + + fn next(&mut self) -> Option { + if self.n == self.max_len { + None + } else { + let part = self.n / 64; + let bit = self.n - (64 * part); + self.n += 1; + + Some(self.s.as_ref()[part] & (1 << bit) > 0) + } + } +} diff --git a/ff/src/fields/arithmetic.rs b/ff/src/fields/arithmetic.rs index 3e02dd0db..431cab879 100644 --- a/ff/src/fields/arithmetic.rs +++ b/ff/src/fields/arithmetic.rs @@ -26,6 +26,75 @@ macro_rules! impl_additive_ops_from_ref { } } + impl<'b, P: $params> core::ops::Add<$type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn add(self, mut other: $type

) -> $type

{ + other.add_assign(self); + other + } + } + + #[allow(unused_qualifications)] + impl<'a, 'b, P: $params> core::ops::Add<&'a $type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn add(self, other: &'a $type

) -> $type

{ + let mut result = *self; + result.add_assign(&*other); + result + } + } + + #[allow(unused_qualifications)] + impl<'a, 'b, P: $params> core::ops::Add<&'a mut $type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn add(self, other: &'a mut $type

) -> $type

{ + let mut result = *self; + result.add_assign(&*other); + result + } + } + + impl<'b, P: $params> core::ops::Sub<$type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn sub(self, other: $type

) -> $type

{ + let mut result = *self; + result.sub_assign(&other); + result + } + } + + #[allow(unused_qualifications)] + impl<'a, 'b, P: $params> core::ops::Sub<&'a $type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn sub(self, other: &'a $type

) -> $type

{ + let mut result = *self; + result.sub_assign(&*other); + result + } + } + + #[allow(unused_qualifications)] + impl<'a, 'b, P: $params> core::ops::Sub<&'a mut $type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn sub(self, other: &'a mut $type

) -> $type

{ + let mut result = *self; + result.sub_assign(&*other); + result + } + } + #[allow(unused_qualifications)] impl core::ops::Sub for $type

{ type Output = Self; @@ -94,7 +163,7 @@ macro_rules! impl_additive_ops_from_ref { }; } -// Implements AddAssign on Self by deferring to an implementation on &Self +// Implements `MulAssign` and `DivAssign` by deferring to an implementation on &Self #[macro_export] macro_rules! impl_multiplicative_ops_from_ref { ($type: ident, $params: ident) => { @@ -146,6 +215,75 @@ macro_rules! impl_multiplicative_ops_from_ref { } } + impl<'b, P: $params> core::ops::Mul<$type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn mul(self, mut other: $type

) -> $type

{ + other.mul_assign(self); + other + } + } + + #[allow(unused_qualifications)] + impl<'a, 'b, P: $params> core::ops::Mul<&'a $type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn mul(self, other: &'a $type

) -> $type

{ + let mut result = *self; + result.mul_assign(&*other); + result + } + } + + #[allow(unused_qualifications)] + impl<'a, 'b, P: $params> core::ops::Mul<&'a mut $type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn mul(self, other: &'a mut $type

) -> $type

{ + let mut result = *self; + result.mul_assign(&*other); + result + } + } + + impl<'b, P: $params> core::ops::Div<$type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn div(self, other: $type

) -> $type

{ + let mut result = *self; + result.div_assign(&other); + result + } + } + + #[allow(unused_qualifications)] + impl<'a, 'b, P: $params> core::ops::Div<&'a $type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn div(self, other: &'a $type

) -> $type

{ + let mut result = *self; + result.div_assign(&*other); + result + } + } + + #[allow(unused_qualifications)] + impl<'a, 'b, P: $params> core::ops::Div<&'a mut $type

> for &'b $type

{ + type Output = $type

; + + #[inline] + fn div(self, other: &'a mut $type

) -> $type

{ + let mut result = *self; + result.div_assign(&*other); + result + } + } + #[allow(unused_qualifications)] impl core::iter::Product for $type

{ fn product>(iter: I) -> Self { diff --git a/ff/src/fields/cyclotomic.rs b/ff/src/fields/cyclotomic.rs new file mode 100644 index 000000000..2d72fa6f0 --- /dev/null +++ b/ff/src/fields/cyclotomic.rs @@ -0,0 +1,123 @@ +/// 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: crate::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`](crate::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`](crate::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 { + 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, + crate::bits::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: &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; +} diff --git a/ff/src/fields/fft_friendly.rs b/ff/src/fields/fft_friendly.rs new file mode 100644 index 000000000..8a2a5bbdd --- /dev/null +++ b/ff/src/fields/fft_friendly.rs @@ -0,0 +1,83 @@ +/// The interface for fields that are able to be used in FFTs. +pub trait FftField: crate::Field { + /// The generator of the multiplicative group of the field + const GENERATOR: Self; + + /// Let `N` be the size of the multiplicative group defined by the field. + /// Then `TWO_ADICITY` is the two-adicity of `N`, i.e. the integer `s` + /// such that `N = 2^s * t` for some odd integer `t`. + const TWO_ADICITY: u32; + + /// 2^s root of unity computed by GENERATOR^t + const TWO_ADIC_ROOT_OF_UNITY: Self; + + /// An integer `b` such that there exists a multiplicative subgroup + /// of size `b^k` for some integer `k`. + const SMALL_SUBGROUP_BASE: Option = None; + + /// The integer `k` such that there exists a multiplicative subgroup + /// of size `Self::SMALL_SUBGROUP_BASE^k`. + const SMALL_SUBGROUP_BASE_ADICITY: Option = None; + + /// GENERATOR^((MODULUS-1) / (2^s * + /// SMALL_SUBGROUP_BASE^SMALL_SUBGROUP_BASE_ADICITY)) Used for mixed-radix + /// FFT. + const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; + + /// Returns the root of unity of order n, if one exists. + /// If no small multiplicative subgroup is defined, this is the 2-adic root + /// of unity of order n (for n a power of 2). + /// If a small multiplicative subgroup is defined, this is the root of unity + /// of order n for the larger subgroup generated by + /// `FftConfig::LARGE_SUBGROUP_ROOT_OF_UNITY` + /// (for n = 2^i * FftConfig::SMALL_SUBGROUP_BASE^j for some i, j). + fn get_root_of_unity(n: u64) -> Option { + let mut omega: Self; + if let Some(large_subgroup_root_of_unity) = Self::LARGE_SUBGROUP_ROOT_OF_UNITY { + let q = Self::SMALL_SUBGROUP_BASE.expect( + "LARGE_SUBGROUP_ROOT_OF_UNITY should only be set in conjunction with SMALL_SUBGROUP_BASE", + ) as u64; + let small_subgroup_base_adicity = Self::SMALL_SUBGROUP_BASE_ADICITY.expect( + "LARGE_SUBGROUP_ROOT_OF_UNITY should only be set in conjunction with SMALL_SUBGROUP_BASE_ADICITY", + ); + + let q_adicity = crate::utils::k_adicity(q, n); + let q_part = q.checked_pow(q_adicity)?; + + let two_adicity = crate::utils::k_adicity(2, n); + let two_part = 2u64.checked_pow(two_adicity)?; + + if n != two_part * q_part + || (two_adicity > Self::TWO_ADICITY) + || (q_adicity > small_subgroup_base_adicity) + { + return None; + } + + omega = large_subgroup_root_of_unity; + for _ in q_adicity..small_subgroup_base_adicity { + omega = omega.pow(&[q as u64]); + } + + for _ in two_adicity..Self::TWO_ADICITY { + omega.square_in_place(); + } + } else { + // Compute the next power of 2. + let size = n.next_power_of_two() as u64; + let log_size_of_group = ark_std::log2(usize::try_from(size).expect("too large")); + + if n != size || log_size_of_group > Self::TWO_ADICITY { + return None; + } + + // Compute the generator for the multiplicative subgroup. + // It should be 2^(log_size_of_group) root of unity. + omega = Self::TWO_ADIC_ROOT_OF_UNITY; + for _ in log_size_of_group..Self::TWO_ADICITY { + omega.square_in_place(); + } + } + Some(omega) + } +} diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index 3fe511bc0..ef58117d8 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -1,19 +1,16 @@ -use crate::{biginteger::BigInteger, fields::utils::k_adicity, UniformRand}; +use crate::UniformRand; use ark_serialize::{ CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, CanonicalSerializeWithFlags, EmptyFlags, Flags, }; use ark_std::{ - cmp::min, fmt::{Debug, Display}, hash::Hash, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, - str::FromStr, vec::Vec, }; pub use ark_ff_macros; -use num_bigint::BigUint; use num_traits::{One, Zero}; use zeroize::Zeroize; @@ -28,6 +25,18 @@ pub use self::models::*; pub mod field_hashers; +mod prime; +pub use prime::*; + +mod fft_friendly; +pub use fft_friendly::*; + +mod cyclotomic; +pub use cyclotomic::*; + +mod sqrt; +pub use sqrt::*; + #[cfg(feature = "parallel")] use ark_std::cmp::max; #[cfg(feature = "parallel")] @@ -262,7 +271,7 @@ pub trait Field: fn pow>(&self, exp: S) -> Self { let mut res = Self::one(); - for i in BitIteratorBE::without_leading_zeros(exp) { + for i in crate::BitIteratorBE::without_leading_zeros(exp) { res.square_in_place(); if i { @@ -282,7 +291,7 @@ pub trait Field: #[inline] fn pow_with_table>(powers_of_2: &[Self], exp: S) -> Option { let mut res = Self::one(); - for (pow, bit) in BitIteratorLE::without_trailing_zeros(exp).enumerate() { + for (pow, bit) in crate::BitIteratorLE::without_trailing_zeros(exp).enumerate() { if bit { res *= powers_of_2.get(pow)?; } @@ -291,539 +300,6 @@ 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 { - 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: &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 - const GENERATOR: Self; - - /// Let `N` be the size of the multiplicative group defined by the field. - /// Then `TWO_ADICITY` is the two-adicity of `N`, i.e. the integer `s` - /// such that `N = 2^s * t` for some odd integer `t`. - const TWO_ADICITY: u32; - - /// 2^s root of unity computed by GENERATOR^t - const TWO_ADIC_ROOT_OF_UNITY: Self; - - /// An integer `b` such that there exists a multiplicative subgroup - /// of size `b^k` for some integer `k`. - const SMALL_SUBGROUP_BASE: Option = None; - - /// The integer `k` such that there exists a multiplicative subgroup - /// of size `Self::SMALL_SUBGROUP_BASE^k`. - const SMALL_SUBGROUP_BASE_ADICITY: Option = None; - - /// GENERATOR^((MODULUS-1) / (2^s * - /// SMALL_SUBGROUP_BASE^SMALL_SUBGROUP_BASE_ADICITY)) Used for mixed-radix - /// FFT. - const LARGE_SUBGROUP_ROOT_OF_UNITY: Option = None; - - /// Returns the root of unity of order n, if one exists. - /// If no small multiplicative subgroup is defined, this is the 2-adic root - /// of unity of order n (for n a power of 2). - /// If a small multiplicative subgroup is defined, this is the root of unity - /// of order n for the larger subgroup generated by - /// `FftConfig::LARGE_SUBGROUP_ROOT_OF_UNITY` - /// (for n = 2^i * FftConfig::SMALL_SUBGROUP_BASE^j for some i, j). - fn get_root_of_unity(n: u64) -> Option { - let mut omega: Self; - if let Some(large_subgroup_root_of_unity) = Self::LARGE_SUBGROUP_ROOT_OF_UNITY { - let q = Self::SMALL_SUBGROUP_BASE.expect( - "LARGE_SUBGROUP_ROOT_OF_UNITY should only be set in conjunction with SMALL_SUBGROUP_BASE", - ) as u64; - let small_subgroup_base_adicity = Self::SMALL_SUBGROUP_BASE_ADICITY.expect( - "LARGE_SUBGROUP_ROOT_OF_UNITY should only be set in conjunction with SMALL_SUBGROUP_BASE_ADICITY", - ); - - let q_adicity = k_adicity(q, n); - let q_part = q.checked_pow(q_adicity)?; - - let two_adicity = k_adicity(2, n); - let two_part = 2u64.checked_pow(two_adicity)?; - - if n != two_part * q_part - || (two_adicity > Self::TWO_ADICITY) - || (q_adicity > small_subgroup_base_adicity) - { - return None; - } - - omega = large_subgroup_root_of_unity; - for _ in q_adicity..small_subgroup_base_adicity { - omega = omega.pow(&[q as u64]); - } - - for _ in two_adicity..Self::TWO_ADICITY { - omega.square_in_place(); - } - } else { - // Compute the next power of 2. - let size = n.next_power_of_two() as u64; - let log_size_of_group = ark_std::log2(usize::try_from(size).expect("too large")); - - if n != size || log_size_of_group > Self::TWO_ADICITY { - return None; - } - - // Compute the generator for the multiplicative subgroup. - // It should be 2^(log_size_of_group) root of unity. - omega = Self::TWO_ADIC_ROOT_OF_UNITY; - for _ in log_size_of_group..Self::TWO_ADICITY { - omega.square_in_place(); - } - } - Some(omega) - } -} - -/// The interface for a prime field, i.e. the field of integers modulo a prime $p$. -/// In the following example we'll use the prime field underlying the BLS12-381 G1 curve. -/// ```rust -/// use ark_ff::{Field, PrimeField, BigInteger}; -/// use ark_test_curves::bls12_381::Fq as F; -/// use ark_std::{One, Zero, UniformRand, test_rng}; -/// -/// let mut rng = test_rng(); -/// let a = F::rand(&mut rng); -/// // We can access the prime modulus associated with `F`: -/// let modulus = ::MODULUS; -/// assert_eq!(a.pow(&modulus), a); // the Euler-Fermat theorem tells us: a^{p-1} = 1 mod p -/// -/// // We can convert field elements to integers in the range [0, MODULUS - 1]: -/// let one: num_bigint::BigUint = F::one().into(); -/// assert_eq!(one, num_bigint::BigUint::one()); -/// -/// // We can construct field elements from an arbitrary sequence of bytes: -/// let n = F::from_le_bytes_mod_order(&modulus.to_bytes_le()); -/// assert_eq!(n, F::zero()); -/// ``` -pub trait PrimeField: - Field - + FftField - + FromStr - + From<::BigInt> - + Into<::BigInt> - + From - + Into -{ - /// A `BigInteger` type that can represent elements of this field. - type BigInt: BigInteger; - - /// The modulus `p`. - const MODULUS: Self::BigInt; - - /// The value `(p - 1)/ 2`. - const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt; - - /// The size of the modulus in bits. - const MODULUS_BIT_SIZE: u32; - - /// The trace of the field is defined as the smallest integer `t` such that by - /// `2^s * t = p - 1`, and `t` is coprime to 2. - const TRACE: Self::BigInt; - /// The value `(t - 1)/ 2`. - const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt; - - /// Construct a prime field element from an integer in the range 0..(p - 1). - fn from_bigint(repr: Self::BigInt) -> Option; - - /// Converts an element of the prime field into an integer in the range 0..(p - 1). - fn into_bigint(self) -> Self::BigInt; - - /// Reads bytes in big-endian, and converts them to a field element. - /// If the integer represented by `bytes` is larger than the modulus `p`, this method - /// performs the appropriate reduction. - fn from_be_bytes_mod_order(bytes: &[u8]) -> Self { - let num_modulus_bytes = ((Self::MODULUS_BIT_SIZE + 7) / 8) as usize; - let num_bytes_to_directly_convert = min(num_modulus_bytes - 1, bytes.len()); - // Copy the leading big-endian bytes directly into a field element. - // The number of bytes directly converted must be less than the - // number of bytes needed to represent the modulus, as we must begin - // modular reduction once the data is of the same number of bytes as the - // modulus. - let mut bytes_to_directly_convert = Vec::new(); - bytes_to_directly_convert.extend(bytes[..num_bytes_to_directly_convert].iter().rev()); - // Guaranteed to not be None, as the input is less than the modulus size. - let mut res = Self::from_random_bytes(&bytes_to_directly_convert).unwrap(); - - // Update the result, byte by byte. - // We go through existing field arithmetic, which handles the reduction. - // TODO: If we need higher speeds, parse more bytes at once, or implement - // modular multiplication by a u64 - let window_size = Self::from(256u64); - for byte in bytes[num_bytes_to_directly_convert..].iter() { - res *= window_size; - res += Self::from(*byte); - } - res - } - - /// Reads bytes in little-endian, and converts them to a field element. - /// If the integer represented by `bytes` is larger than the modulus `p`, this method - /// performs the appropriate reduction. - fn from_le_bytes_mod_order(bytes: &[u8]) -> Self { - let mut bytes_copy = bytes.to_vec(); - bytes_copy.reverse(); - Self::from_be_bytes_mod_order(&bytes_copy) - } -} - -/// Indication of the field element's quadratic residuosity -/// -/// # Examples -/// ``` -/// # use ark_std::test_rng; -/// # use ark_std::UniformRand; -/// # use ark_test_curves::{LegendreSymbol, Field, bls12_381::Fq as Fp}; -/// let a: Fp = Fp::rand(&mut test_rng()); -/// let b = a.square(); -/// assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); -/// ``` -#[derive(Debug, PartialEq, Eq)] -pub enum LegendreSymbol { - Zero = 0, - QuadraticResidue = 1, - QuadraticNonResidue = -1, -} - -impl LegendreSymbol { - /// Returns true if `self.is_zero()`. - /// - /// # Examples - /// ``` - /// # use ark_std::test_rng; - /// # use ark_std::UniformRand; - /// # use ark_test_curves::{LegendreSymbol, Field, bls12_381::Fq as Fp}; - /// let a: Fp = Fp::rand(&mut test_rng()); - /// let b: Fp = a.square(); - /// assert!(!b.legendre().is_zero()); - /// ``` - pub fn is_zero(&self) -> bool { - *self == LegendreSymbol::Zero - } - - /// Returns true if `self` is a quadratic non-residue. - /// - /// # Examples - /// ``` - /// # use ark_test_curves::{Fp2Config, Field, LegendreSymbol, bls12_381::{Fq, Fq2Config}}; - /// let a: Fq = Fq2Config::NONRESIDUE; - /// assert!(a.legendre().is_qnr()); - /// ``` - pub fn is_qnr(&self) -> bool { - *self == LegendreSymbol::QuadraticNonResidue - } - - /// Returns true if `self` is a quadratic residue. - /// # Examples - /// ``` - /// # use ark_std::test_rng; - /// # use ark_test_curves::bls12_381::Fq as Fp; - /// # use ark_std::UniformRand; - /// # use ark_ff::{LegendreSymbol, Field}; - /// let a: Fp = Fp::rand(&mut test_rng()); - /// let b: Fp = a.square(); - /// assert!(b.legendre().is_qr()); - /// ``` - pub fn is_qr(&self) -> bool { - *self == LegendreSymbol::QuadraticResidue - } -} - -/// Precomputation that makes computing square roots faster -/// A particular variant should only be instantiated if the modulus satisfies -/// the corresponding condition. -#[non_exhaustive] -pub enum SqrtPrecomputation { - // Tonelli-Shanks algorithm works for all elements, no matter what the modulus is. - TonelliShanks { - two_adicity: u32, - quadratic_nonresidue_to_trace: F, - trace_of_modulus_minus_one_div_two: &'static [u64], - }, - /// To be used when the modulus is 3 mod 4. - Case3Mod4 { - modulus_plus_one_div_four: &'static [u64], - }, -} - -impl SqrtPrecomputation { - fn sqrt(&self, elem: &F) -> Option { - match self { - Self::TonelliShanks { - two_adicity, - quadratic_nonresidue_to_trace, - trace_of_modulus_minus_one_div_two, - } => { - // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) - // Actually this is just normal Tonelli-Shanks; since `P::Generator` - // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` - // is also a quadratic non-residue (since `t` is odd). - if elem.is_zero() { - return Some(F::zero()); - } - // Try computing the square root (x at the end of the algorithm) - // Check at the end of the algorithm if x was a square root - // Begin Tonelli-Shanks - let mut z = *quadratic_nonresidue_to_trace; - let mut w = elem.pow(trace_of_modulus_minus_one_div_two); - let mut x = w * elem; - let mut b = x * &w; - - let mut v = *two_adicity as usize; - - while !b.is_one() { - let mut k = 0usize; - - let mut b2k = b; - while !b2k.is_one() { - // invariant: b2k = b^(2^k) after entering this loop - b2k.square_in_place(); - k += 1; - } - - if k == (*two_adicity as usize) { - // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1, - // which means that no square root exists. - return None; - } - let j = v - k; - w = z; - for _ in 1..j { - w.square_in_place(); - } - - z = w.square(); - b *= &z; - x *= &w; - v = k; - } - // Is x the square root? If so, return it. - if x.square() == *elem { - Some(x) - } else { - // Consistency check that if no square root is found, - // it is because none exists. - debug_assert!(!matches!(elem.legendre(), LegendreSymbol::QuadraticResidue)); - None - } - }, - Self::Case3Mod4 { - modulus_plus_one_div_four, - } => { - let result = elem.pow(modulus_plus_one_div_four.as_ref()); - (result.square() == *elem).then_some(result) - }, - } - } -} - -/// Iterates over a slice of `u64` in *big-endian* order. -#[derive(Debug)] -pub struct BitIteratorBE> { - s: Slice, - n: usize, -} - -impl> BitIteratorBE { - pub fn new(s: Slice) -> Self { - let n = s.as_ref().len() * 64; - BitIteratorBE { s, n } - } - - /// Construct an iterator that automatically skips any leading zeros. - /// That is, it skips all zeros before the most-significant one. - pub fn without_leading_zeros(s: Slice) -> impl Iterator { - Self::new(s).skip_while(|b| !b) - } -} - -impl> Iterator for BitIteratorBE { - type Item = bool; - - fn next(&mut self) -> Option { - if self.n == 0 { - None - } else { - self.n -= 1; - let part = self.n / 64; - let bit = self.n - (64 * part); - - Some(self.s.as_ref()[part] & (1 << bit) > 0) - } - } -} - -/// Iterates over a slice of `u64` in *little-endian* order. -#[derive(Debug)] -pub struct BitIteratorLE> { - s: Slice, - n: usize, - max_len: usize, -} - -impl> BitIteratorLE { - pub fn new(s: Slice) -> Self { - let n = 0; - let max_len = s.as_ref().len() * 64; - BitIteratorLE { s, n, max_len } - } - - /// Construct an iterator that automatically skips any trailing zeros. - /// That is, it skips all zeros after the most-significant one. - pub fn without_trailing_zeros(s: Slice) -> impl Iterator { - let mut first_trailing_zero = 0; - for (i, limb) in s.as_ref().iter().enumerate().rev() { - first_trailing_zero = i * 64 + (64 - limb.leading_zeros()) as usize; - if *limb != 0 { - break; - } - } - let mut iter = Self::new(s); - iter.max_len = first_trailing_zero; - iter - } -} - -impl> Iterator for BitIteratorLE { - type Item = bool; - - fn next(&mut self) -> Option { - if self.n == self.max_len { - None - } else { - let part = self.n / 64; - let bit = self.n - (64 * part); - self.n += 1; - - Some(self.s.as_ref()[part] & (1 << bit) > 0) - } - } -} - // Given a vector of field elements {v_i}, compute the vector {v_i^(-1)} pub fn batch_inversion(v: &mut [F]) { batch_inversion_and_mul(v, &F::one()); @@ -891,7 +367,7 @@ fn serial_batch_inversion_and_mul(v: &mut [F], coeff: &F) { #[cfg(all(test, feature = "std"))] mod std_tests { - use super::BitIteratorLE; + use crate::BitIteratorLE; #[test] fn bit_iterator_le() { @@ -911,7 +387,10 @@ mod std_tests { #[cfg(test)] mod no_std_tests { use super::*; + use ark_std::str::FromStr; use ark_std::test_rng; + use num_bigint::*; + // TODO: only Fr & FrConfig should need to be imported. // The rest of imports are caused by cargo not resolving the deps properly // from this crate and from ark_test_curves diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index cd599e786..bd776a212 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -734,6 +734,50 @@ impl<'a, P: FpConfig, const N: usize> Div<&'a Fp> for Fp { } } +impl<'a, 'b, P: FpConfig, const N: usize> Add<&'b Fp> for &'a Fp { + type Output = Fp; + + #[inline] + fn add(self, other: &'b Fp) -> Fp { + let mut result = *self; + result.add_assign(other); + result + } +} + +impl<'a, 'b, P: FpConfig, const N: usize> Sub<&'b Fp> for &'a Fp { + type Output = Fp; + + #[inline] + fn sub(self, other: &Fp) -> Fp { + let mut result = *self; + result.sub_assign(other); + result + } +} + +impl<'a, 'b, P: FpConfig, const N: usize> Mul<&'b Fp> for &'a Fp { + type Output = Fp; + + #[inline] + fn mul(self, other: &Fp) -> Fp { + let mut result = *self; + result.mul_assign(other); + result + } +} + +impl<'a, 'b, P: FpConfig, const N: usize> Div<&'b Fp> for &'a Fp { + type Output = Fp; + + #[inline] + fn div(self, other: &Fp) -> Fp { + let mut result = *self; + result.div_assign(other); + result + } +} + impl<'a, P: FpConfig, const N: usize> AddAssign<&'a Self> for Fp { #[inline] fn add_assign(&mut self, other: &Self) { diff --git a/ff/src/fields/prime.rs b/ff/src/fields/prime.rs new file mode 100644 index 000000000..ce099469d --- /dev/null +++ b/ff/src/fields/prime.rs @@ -0,0 +1,96 @@ +use crate::{BigInteger, FftField, Field}; + +use ark_std::{cmp::min, str::FromStr, vec::Vec}; +use num_bigint::BigUint; + +/// The interface for a prime field, i.e. the field of integers modulo a prime $p$. +/// In the following example we'll use the prime field underlying the BLS12-381 G1 curve. +/// ```rust +/// use ark_ff::{Field, PrimeField, BigInteger}; +/// use ark_test_curves::bls12_381::Fq as F; +/// use ark_std::{One, Zero, UniformRand, test_rng}; +/// +/// let mut rng = test_rng(); +/// let a = F::rand(&mut rng); +/// // We can access the prime modulus associated with `F`: +/// let modulus = ::MODULUS; +/// assert_eq!(a.pow(&modulus), a); // the Euler-Fermat theorem tells us: a^{p-1} = 1 mod p +/// +/// // We can convert field elements to integers in the range [0, MODULUS - 1]: +/// let one: num_bigint::BigUint = F::one().into(); +/// assert_eq!(one, num_bigint::BigUint::one()); +/// +/// // We can construct field elements from an arbitrary sequence of bytes: +/// let n = F::from_le_bytes_mod_order(&modulus.to_bytes_le()); +/// assert_eq!(n, F::zero()); +/// ``` +pub trait PrimeField: + Field + + FftField + + FromStr + + From<::BigInt> + + Into<::BigInt> + + From + + Into +{ + /// A `BigInteger` type that can represent elements of this field. + type BigInt: BigInteger; + + /// The modulus `p`. + const MODULUS: Self::BigInt; + + /// The value `(p - 1)/ 2`. + const MODULUS_MINUS_ONE_DIV_TWO: Self::BigInt; + + /// The size of the modulus in bits. + const MODULUS_BIT_SIZE: u32; + + /// The trace of the field is defined as the smallest integer `t` such that by + /// `2^s * t = p - 1`, and `t` is coprime to 2. + const TRACE: Self::BigInt; + /// The value `(t - 1)/ 2`. + const TRACE_MINUS_ONE_DIV_TWO: Self::BigInt; + + /// Construct a prime field element from an integer in the range 0..(p - 1). + fn from_bigint(repr: Self::BigInt) -> Option; + + /// Converts an element of the prime field into an integer in the range 0..(p - 1). + fn into_bigint(self) -> Self::BigInt; + + /// Reads bytes in big-endian, and converts them to a field element. + /// If the integer represented by `bytes` is larger than the modulus `p`, this method + /// performs the appropriate reduction. + fn from_be_bytes_mod_order(bytes: &[u8]) -> Self { + let num_modulus_bytes = ((Self::MODULUS_BIT_SIZE + 7) / 8) as usize; + let num_bytes_to_directly_convert = min(num_modulus_bytes - 1, bytes.len()); + // Copy the leading big-endian bytes directly into a field element. + // The number of bytes directly converted must be less than the + // number of bytes needed to represent the modulus, as we must begin + // modular reduction once the data is of the same number of bytes as the + // modulus. + let mut bytes_to_directly_convert = Vec::new(); + bytes_to_directly_convert.extend(bytes[..num_bytes_to_directly_convert].iter().rev()); + // Guaranteed to not be None, as the input is less than the modulus size. + let mut res = Self::from_random_bytes(&bytes_to_directly_convert).unwrap(); + + // Update the result, byte by byte. + // We go through existing field arithmetic, which handles the reduction. + // TODO: If we need higher speeds, parse more bytes at once, or implement + // modular multiplication by a u64 + let window_size = Self::from(256u64); + for byte in bytes[num_bytes_to_directly_convert..].iter() { + res *= window_size; + res += Self::from(*byte); + } + res + } + + /// Reads bytes in little-endian, and converts them to a field element. + /// If the integer represented by `bytes` is larger than the modulus `p`, this method + /// performs the appropriate reduction. + fn from_le_bytes_mod_order(bytes: &[u8]) -> Self { + let mut bytes_copy = bytes.to_vec(); + bytes_copy.reverse(); + Self::from_be_bytes_mod_order(&bytes_copy) + } +} diff --git a/ff/src/fields/sqrt.rs b/ff/src/fields/sqrt.rs new file mode 100644 index 000000000..6f3525988 --- /dev/null +++ b/ff/src/fields/sqrt.rs @@ -0,0 +1,149 @@ +/// Indication of the field element's quadratic residuosity +/// +/// # Examples +/// ``` +/// # use ark_std::test_rng; +/// # use ark_std::UniformRand; +/// # use ark_test_curves::{LegendreSymbol, Field, bls12_381::Fq as Fp}; +/// let a: Fp = Fp::rand(&mut test_rng()); +/// let b = a.square(); +/// assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); +/// ``` +#[derive(Debug, PartialEq, Eq)] +pub enum LegendreSymbol { + Zero = 0, + QuadraticResidue = 1, + QuadraticNonResidue = -1, +} + +impl LegendreSymbol { + /// Returns true if `self.is_zero()`. + /// + /// # Examples + /// ``` + /// # use ark_std::test_rng; + /// # use ark_std::UniformRand; + /// # use ark_test_curves::{LegendreSymbol, Field, bls12_381::Fq as Fp}; + /// let a: Fp = Fp::rand(&mut test_rng()); + /// let b: Fp = a.square(); + /// assert!(!b.legendre().is_zero()); + /// ``` + pub fn is_zero(&self) -> bool { + *self == LegendreSymbol::Zero + } + + /// Returns true if `self` is a quadratic non-residue. + /// + /// # Examples + /// ``` + /// # use ark_test_curves::{Fp2Config, Field, LegendreSymbol, bls12_381::{Fq, Fq2Config}}; + /// let a: Fq = Fq2Config::NONRESIDUE; + /// assert!(a.legendre().is_qnr()); + /// ``` + pub fn is_qnr(&self) -> bool { + *self == LegendreSymbol::QuadraticNonResidue + } + + /// Returns true if `self` is a quadratic residue. + /// # Examples + /// ``` + /// # use ark_std::test_rng; + /// # use ark_test_curves::bls12_381::Fq as Fp; + /// # use ark_std::UniformRand; + /// # use ark_ff::{LegendreSymbol, Field}; + /// let a: Fp = Fp::rand(&mut test_rng()); + /// let b: Fp = a.square(); + /// assert!(b.legendre().is_qr()); + /// ``` + pub fn is_qr(&self) -> bool { + *self == LegendreSymbol::QuadraticResidue + } +} + +/// Precomputation that makes computing square roots faster +/// A particular variant should only be instantiated if the modulus satisfies +/// the corresponding condition. +#[non_exhaustive] +pub enum SqrtPrecomputation { + // Tonelli-Shanks algorithm works for all elements, no matter what the modulus is. + TonelliShanks { + two_adicity: u32, + quadratic_nonresidue_to_trace: F, + trace_of_modulus_minus_one_div_two: &'static [u64], + }, + /// To be used when the modulus is 3 mod 4. + Case3Mod4 { + modulus_plus_one_div_four: &'static [u64], + }, +} + +impl SqrtPrecomputation { + pub fn sqrt(&self, elem: &F) -> Option { + match self { + Self::TonelliShanks { + two_adicity, + quadratic_nonresidue_to_trace, + trace_of_modulus_minus_one_div_two, + } => { + // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) + // Actually this is just normal Tonelli-Shanks; since `P::Generator` + // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t` + // is also a quadratic non-residue (since `t` is odd). + if elem.is_zero() { + return Some(F::zero()); + } + // Try computing the square root (x at the end of the algorithm) + // Check at the end of the algorithm if x was a square root + // Begin Tonelli-Shanks + let mut z = *quadratic_nonresidue_to_trace; + let mut w = elem.pow(trace_of_modulus_minus_one_div_two); + let mut x = w * elem; + let mut b = x * &w; + + let mut v = *two_adicity as usize; + + while !b.is_one() { + let mut k = 0usize; + + let mut b2k = b; + while !b2k.is_one() { + // invariant: b2k = b^(2^k) after entering this loop + b2k.square_in_place(); + k += 1; + } + + if k == (*two_adicity as usize) { + // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1, + // which means that no square root exists. + return None; + } + let j = v - k; + w = z; + for _ in 1..j { + w.square_in_place(); + } + + z = w.square(); + b *= &z; + x *= &w; + v = k; + } + // Is x the square root? If so, return it. + if x.square() == *elem { + Some(x) + } else { + // Consistency check that if no square root is found, + // it is because none exists. + debug_assert!(!matches!(elem.legendre(), LegendreSymbol::QuadraticResidue)); + None + } + }, + Self::Case3Mod4 { + modulus_plus_one_div_four, + } => { + let result = elem.pow(modulus_plus_one_div_four.as_ref()); + (result.square() == *elem).then_some(result) + }, + } + } +} diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 44771e3b4..9a2d5bdf3 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -25,6 +25,9 @@ pub use self::biginteger::*; pub mod fields; pub use self::fields::*; +pub(crate) mod bits; +pub use bits::*; + pub(crate) mod const_helpers; pub use ark_std::UniformRand;