#![allow(clippy::module_inception)]
#![forbid(unsafe_code)]
#[macro_use]
extern crate derivative;
#[macro_use]
extern crate thiserror;
#[macro_use]
mod macros;
pub mod errors;
pub use errors::*;
mod fp_256;
pub use fp_256::*;
mod fp_384;
pub use fp_384::*;
mod fp2;
pub use fp2::*;
pub mod fp6_3over2;
mod fp12_2over3over2;
pub use fp12_2over3over2::*;
mod legendre;
pub use legendre::*;
mod to_field_vec;
pub use to_field_vec::*;
pub mod traits;
pub use traits::*;
use snarkvm_utilities::{
biginteger::*,
serialize::{CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, CanonicalSerializeWithFlags},
FromBytes,
ToBytes,
};
impl_field_to_biginteger!(Fp256, BigInteger256, Fp256Parameters);
impl_field_to_biginteger!(Fp384, BigInteger384, Fp384Parameters);
impl_primefield_serializer!(Fp256, Fp256Parameters, 32);
impl_primefield_serializer!(Fp384, Fp384Parameters, 48);
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) {
use rayon::prelude::*;
let min_elements_per_thread = 1;
let num_cpus_available = snarkvm_utilities::parallel::max_available_threads();
let num_elems = v.len();
let num_elem_per_thread = min_elements_per_thread.max(num_elems / num_cpus_available);
v.par_chunks_mut(num_elem_per_thread).for_each(|chunk| {
serial_batch_inversion_and_mul(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;
}
}