use crate::UniformRand;
use ark_serialize::{
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
CanonicalSerializeWithFlags, EmptyFlags, Flags,
};
use ark_std::{
fmt::{Debug, Display},
hash::Hash,
iter::*,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
vec::*,
};
pub use ark_ff_macros;
pub use num_traits::{One, Zero};
use zeroize::Zeroize;
pub mod utils;
#[macro_use]
pub mod arithmetic;
#[macro_use]
pub mod models;
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")]
use rayon::prelude::*;
pub trait AdditiveGroup:
Eq
+ 'static
+ Sized
+ CanonicalSerialize
+ CanonicalDeserialize
+ Copy
+ Clone
+ Default
+ Send
+ Sync
+ Hash
+ Debug
+ Display
+ UniformRand
+ Zeroize
+ Zero
+ Neg<Output = Self>
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Mul<<Self as AdditiveGroup>::Scalar, Output = Self>
+ AddAssign<Self>
+ SubAssign<Self>
+ MulAssign<<Self as AdditiveGroup>::Scalar>
+ for<'a> Add<&'a Self, Output = Self>
+ for<'a> Sub<&'a Self, Output = Self>
+ for<'a> Mul<&'a <Self as AdditiveGroup>::Scalar, Output = Self>
+ for<'a> AddAssign<&'a Self>
+ for<'a> SubAssign<&'a Self>
+ for<'a> MulAssign<&'a <Self as AdditiveGroup>::Scalar>
+ for<'a> Add<&'a mut Self, Output = Self>
+ for<'a> Sub<&'a mut Self, Output = Self>
+ for<'a> Mul<&'a mut <Self as AdditiveGroup>::Scalar, Output = Self>
+ for<'a> AddAssign<&'a mut Self>
+ for<'a> SubAssign<&'a mut Self>
+ for<'a> MulAssign<&'a mut <Self as AdditiveGroup>::Scalar>
+ ark_std::iter::Sum<Self>
+ for<'a> ark_std::iter::Sum<&'a Self>
{
type Scalar: Field;
const ZERO: Self;
#[must_use]
fn double(&self) -> Self {
let mut copy = *self;
copy.double_in_place();
copy
}
fn double_in_place(&mut self) -> &mut Self {
self.add_assign(*self);
self
}
fn neg_in_place(&mut self) -> &mut Self {
*self = -(*self);
self
}
}
pub trait Field:
'static
+ Copy
+ Clone
+ Debug
+ Display
+ Default
+ Send
+ Sync
+ Eq
+ Zero
+ One
+ Ord
+ Neg<Output = Self>
+ UniformRand
+ Zeroize
+ Sized
+ Hash
+ CanonicalSerialize
+ CanonicalSerializeWithFlags
+ CanonicalDeserialize
+ CanonicalDeserializeWithFlags
+ AdditiveGroup<Scalar = Self>
+ Div<Self, Output = Self>
+ DivAssign<Self>
+ for<'a> Div<&'a Self, Output = Self>
+ for<'a> DivAssign<&'a Self>
+ for<'a> Div<&'a mut Self, Output = Self>
+ for<'a> DivAssign<&'a mut Self>
+ for<'a> core::iter::Product<&'a Self>
+ From<u128>
+ From<u64>
+ From<u32>
+ From<u16>
+ From<u8>
+ From<i128>
+ From<i64>
+ From<i32>
+ From<i16>
+ From<i8>
+ From<bool>
+ Product<Self>
{
type BasePrimeField: PrimeField;
const SQRT_PRECOMP: Option<SqrtPrecomputation<Self>>;
const ONE: Self;
fn characteristic() -> &'static [u64] {
Self::BasePrimeField::characteristic()
}
fn extension_degree() -> u64;
fn to_base_prime_field_elements(&self) -> impl Iterator<Item = Self::BasePrimeField>;
fn from_base_prime_field_elems(
elems: impl IntoIterator<Item = Self::BasePrimeField>,
) -> Option<Self>;
fn from_base_prime_field(elem: Self::BasePrimeField) -> Self;
fn from_random_bytes(bytes: &[u8]) -> Option<Self> {
Self::from_random_bytes_with_flags::<EmptyFlags>(bytes).map(|f| f.0)
}
fn from_random_bytes_with_flags<F: Flags>(bytes: &[u8]) -> Option<(Self, F)>;
fn legendre(&self) -> LegendreSymbol;
#[must_use]
fn sqrt(&self) -> Option<Self> {
match Self::SQRT_PRECOMP {
Some(tv) => tv.sqrt(self),
None => unimplemented!(),
}
}
fn sqrt_in_place(&mut self) -> Option<&mut Self> {
(*self).sqrt().map(|sqrt| {
*self = sqrt;
self
})
}
#[must_use]
fn square(&self) -> Self;
fn square_in_place(&mut self) -> &mut Self;
#[must_use]
fn inverse(&self) -> Option<Self>;
fn inverse_in_place(&mut self) -> Option<&mut Self>;
#[inline]
fn sum_of_products<const T: usize>(a: &[Self; T], b: &[Self; T]) -> Self {
let mut sum = Self::zero();
for i in 0..a.len() {
sum += a[i] * b[i];
}
sum
}
fn frobenius_map_in_place(&mut self, power: usize);
#[must_use]
fn frobenius_map(&self, power: usize) -> Self {
let mut this = *self;
this.frobenius_map_in_place(power);
this
}
#[must_use]
fn pow<S: AsRef<[u64]>>(&self, exp: S) -> Self {
let mut res = Self::one();
for i in crate::BitIteratorBE::without_leading_zeros(exp) {
res.square_in_place();
if i {
res *= self;
}
}
res
}
#[inline]
fn pow_with_table<S: AsRef<[u64]>>(powers_of_2: &[Self], exp: S) -> Option<Self> {
let mut res = Self::one();
for (pow, bit) in crate::BitIteratorLE::without_trailing_zeros(exp).enumerate() {
if bit {
res *= powers_of_2.get(pow)?;
}
}
Some(res)
}
fn mul_by_base_prime_field(&self, elem: &Self::BasePrimeField) -> Self;
}
pub fn batch_inversion<F: Field>(v: &mut [F]) {
batch_inversion_and_mul(v, &F::one());
}
#[cfg(not(feature = "parallel"))]
pub fn batch_inversion_and_mul<F: Field>(v: &mut [F], coeff: &F) {
serial_batch_inversion_and_mul(v, coeff);
}
#[cfg(feature = "parallel")]
pub fn batch_inversion_and_mul<F: Field>(v: &mut [F], coeff: &F) {
let min_elements_per_thread = 1;
let num_cpus_available = rayon::current_num_threads();
let num_elems = v.len();
let num_elem_per_thread = max(num_elems / num_cpus_available, min_elements_per_thread);
v.par_chunks_mut(num_elem_per_thread).for_each(|mut chunk| {
serial_batch_inversion_and_mul(&mut chunk, coeff);
});
}
fn serial_batch_inversion_and_mul<F: Field>(v: &mut [F], coeff: &F) {
let mut prod = Vec::with_capacity(v.len());
let mut tmp = F::one();
for f in v.iter().filter(|f| !f.is_zero()) {
tmp.mul_assign(f);
prod.push(tmp);
}
tmp = tmp.inverse().unwrap();
tmp *= coeff;
for (f, s) in v.iter_mut()
.rev()
.filter(|f| !f.is_zero())
.zip(prod.into_iter().rev().skip(1).chain(Some(F::one())))
{
let new_tmp = tmp * *f;
*f = tmp * &s;
tmp = new_tmp;
}
}
#[cfg(all(test, feature = "std"))]
mod std_tests {
use crate::BitIteratorLE;
#[test]
fn bit_iterator_le() {
let bits = BitIteratorLE::new(&[0, 1 << 10]).collect::<Vec<_>>();
dbg!(&bits);
assert!(bits[74]);
for (i, bit) in bits.into_iter().enumerate() {
if i != 74 {
assert!(!bit)
} else {
assert!(bit)
}
}
}
}
#[cfg(test)]
mod no_std_tests {
use super::*;
use ark_std::{str::FromStr, test_rng};
use num_bigint::*;
use ark_test_curves::{
ark_ff::{batch_inversion, batch_inversion_and_mul, PrimeField},
bls12_381::Fr,
};
#[test]
fn test_batch_inversion() {
let mut random_coeffs = Vec::<Fr>::new();
let vec_size = 1000;
for _ in 0..=vec_size {
random_coeffs.push(Fr::rand(&mut test_rng()));
}
let mut random_coeffs_inv = random_coeffs.clone();
batch_inversion::<Fr>(&mut random_coeffs_inv);
for i in 0..=vec_size {
assert_eq!(random_coeffs_inv[i] * random_coeffs[i], Fr::one());
}
let rand_multiplier = Fr::rand(&mut test_rng());
let mut random_coeffs_inv_shifted = random_coeffs.clone();
batch_inversion_and_mul(&mut random_coeffs_inv_shifted, &rand_multiplier);
for i in 0..=vec_size {
assert_eq!(
random_coeffs_inv_shifted[i] * random_coeffs[i],
rand_multiplier
);
}
}
#[test]
pub fn test_from_ints() {
let felt2 = Fr::one() + Fr::one();
let felt16 = felt2 * felt2 * felt2 * felt2;
assert_eq!(Fr::from(1u8), Fr::one());
assert_eq!(Fr::from(1u16), Fr::one());
assert_eq!(Fr::from(1u32), Fr::one());
assert_eq!(Fr::from(1u64), Fr::one());
assert_eq!(Fr::from(1u128), Fr::one());
assert_eq!(Fr::from(-1i8), -Fr::one());
assert_eq!(Fr::from(-1i64), -Fr::one());
assert_eq!(Fr::from(0), Fr::zero());
assert_eq!(Fr::from(-16i32), -felt16);
assert_eq!(Fr::from(16u32), felt16);
assert_eq!(Fr::from(16i64), felt16);
assert_eq!(Fr::from(-2i128), -felt2);
assert_eq!(Fr::from(2u16), felt2);
}
#[test]
fn test_from_into_biguint() {
let mut rng = ark_std::test_rng();
let modulus_bits = Fr::MODULUS_BIT_SIZE;
let modulus: num_bigint::BigUint = Fr::MODULUS.into();
let mut rand_bytes = Vec::new();
for _ in 0..(2 * modulus_bits / 8) {
rand_bytes.push(u8::rand(&mut rng));
}
let rand = BigUint::from_bytes_le(&rand_bytes);
let a: BigUint = Fr::from(rand.clone()).into();
let b = rand % modulus;
assert_eq!(a, b);
}
#[test]
fn test_from_be_bytes_mod_order() {
use ark_std::{rand::Rng, string::ToString};
use ark_test_curves::ark_ff::BigInteger;
use num_bigint::BigUint;
let ref_modulus = BigUint::from_bytes_be(&Fr::MODULUS.to_bytes_be());
let mut test_vectors = vec![
vec![0u8],
vec![1u8],
vec![255u8],
vec![1u8, 0u8],
vec![1u8, 0u8, 255u8],
vec![
115u8, 237u8, 167u8, 83u8, 41u8, 157u8, 125u8, 72u8, 51u8, 57u8, 216u8, 8u8, 9u8,
161u8, 216u8, 5u8, 83u8, 189u8, 164u8, 2u8, 255u8, 254u8, 91u8, 254u8, 255u8,
255u8, 255u8, 255u8, 0u8, 0u8, 0u8,
],
vec![
115u8, 237u8, 167u8, 83u8, 41u8, 157u8, 125u8, 72u8, 51u8, 57u8, 216u8, 8u8, 9u8,
161u8, 216u8, 5u8, 83u8, 189u8, 164u8, 2u8, 255u8, 254u8, 91u8, 254u8, 255u8,
255u8, 255u8, 255u8, 0u8, 0u8, 1u8,
],
vec![
115u8, 237u8, 167u8, 83u8, 41u8, 157u8, 125u8, 72u8, 51u8, 57u8, 216u8, 8u8, 9u8,
161u8, 216u8, 5u8, 83u8, 189u8, 164u8, 2u8, 255u8, 254u8, 91u8, 254u8, 255u8,
255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 0u8,
],
vec![
115u8, 237u8, 167u8, 83u8, 41u8, 157u8, 125u8, 72u8, 51u8, 57u8, 216u8, 8u8, 9u8,
161u8, 216u8, 5u8, 83u8, 189u8, 164u8, 2u8, 255u8, 254u8, 91u8, 254u8, 255u8,
255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 1u8,
],
vec![
115u8, 237u8, 167u8, 83u8, 41u8, 157u8, 125u8, 72u8, 51u8, 57u8, 216u8, 8u8, 9u8,
161u8, 216u8, 5u8, 83u8, 189u8, 164u8, 2u8, 255u8, 254u8, 91u8, 254u8, 255u8,
255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 2u8,
],
vec![
231u8, 219u8, 78u8, 166u8, 83u8, 58u8, 250u8, 144u8, 102u8, 115u8, 176u8, 16u8,
19u8, 67u8, 176u8, 10u8, 167u8, 123u8, 72u8, 5u8, 255u8, 252u8, 183u8, 253u8,
255u8, 255u8, 255u8, 254u8, 0u8, 0u8, 0u8, 2u8,
],
vec![
115u8, 237u8, 167u8, 83u8, 41u8, 157u8, 125u8, 72u8, 51u8, 57u8, 216u8, 8u8, 9u8,
161u8, 216u8, 5u8, 83u8, 189u8, 164u8, 2u8, 255u8, 254u8, 91u8, 254u8, 255u8,
255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 1u8, 0u8,
],
vec![
1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
17u8,
],
vec![
1u8, 115u8, 237u8, 167u8, 83u8, 41u8, 157u8, 125u8, 72u8, 51u8, 57u8, 216u8, 8u8,
9u8, 161u8, 216u8, 5u8, 83u8, 189u8, 164u8, 2u8, 255u8, 254u8, 91u8, 254u8, 255u8,
255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 20u8,
],
vec![
1u8, 0u8, 115u8, 237u8, 167u8, 83u8, 41u8, 157u8, 125u8, 72u8, 51u8, 57u8, 216u8,
8u8, 9u8, 161u8, 216u8, 5u8, 83u8, 189u8, 164u8, 2u8, 255u8, 254u8, 91u8, 254u8,
255u8, 255u8, 255u8, 255u8, 0u8, 0u8, 0u8, 82u8,
],
];
for i in 1..512 {
let mut rng = test_rng();
let data: Vec<u8> = (0..i).map(|_| rng.gen()).collect();
test_vectors.push(data);
}
for i in test_vectors {
let mut expected_biguint = BigUint::from_bytes_be(&i);
expected_biguint =
expected_biguint.modpow(&BigUint::from_bytes_be(&[1u8]), &ref_modulus);
let expected_string = expected_biguint.to_string();
let expected = Fr::from_str(&expected_string).unwrap();
let actual = Fr::from_be_bytes_mod_order(&i);
assert_eq!(expected, actual, "failed on test {:?}", i);
}
}
}