use core::iter;
use core::marker::PhantomData;
use crate::field::Field;
use crate::{Algebra, ExtensionField, PackedField};
mod binomial_extension;
mod complex;
mod cubic_extension;
mod packed_binomial_extension;
mod packed_cubic_extension;
mod packed_quintic_extension;
mod quintic_extension;
use alloc::vec::Vec;
pub use binomial_extension::*;
pub use complex::*;
pub use cubic_extension::{CubicTrinomialExtensionField, cubic_square, trinomial_cubic_mul};
pub use packed_binomial_extension::*;
pub use packed_cubic_extension::PackedCubicTrinomialExtensionField;
pub use packed_quintic_extension::PackedQuinticTrinomialExtensionField;
pub use quintic_extension::{
QuinticTrinomialExtensionField, quintic_square, trinomial_quintic_mul,
};
pub trait ExtensionShape: 'static + sealed::Sealed {}
mod sealed {
pub trait Sealed {}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
pub struct Binomial<F>(PhantomData<F>);
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
pub struct CubicTrinomial;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
pub struct QuinticTrinomial;
impl<F: Field> sealed::Sealed for Binomial<F> {}
impl sealed::Sealed for CubicTrinomial {}
impl sealed::Sealed for QuinticTrinomial {}
impl<F: Field> ExtensionShape for Binomial<F> {}
impl ExtensionShape for CubicTrinomial {}
impl ExtensionShape for QuinticTrinomial {}
#[derive(
Copy, Clone, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize, PartialOrd, Ord,
)]
#[repr(transparent)] #[must_use]
pub struct ExtField<F, const D: usize, Shape, A = F> {
#[serde(
with = "p3_util::array_serialization",
bound(
serialize = "A: serde::Serialize",
deserialize = "A: serde::Deserialize<'de>"
)
)]
pub(crate) value: [A; D],
_phantom: PhantomData<(F, Shape)>,
}
impl<F, const D: usize, Shape, A> ExtField<F, D, Shape, A> {
#[inline]
pub const fn new(value: [A; D]) -> Self {
const { assert!(D > 1) }
Self {
value,
_phantom: PhantomData,
}
}
}
#[derive(
Copy, Clone, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize, PartialOrd, Ord,
)]
#[repr(transparent)]
#[must_use]
pub struct PackedExtField<F: Field, PF: PackedField<Scalar = F>, const D: usize, Shape> {
#[serde(
with = "p3_util::array_serialization",
bound(
serialize = "PF: serde::Serialize",
deserialize = "PF: serde::Deserialize<'de>"
)
)]
pub(crate) value: [PF; D],
_phantom: PhantomData<Shape>,
}
impl<F: Field, PF: PackedField<Scalar = F>, const D: usize, Shape> PackedExtField<F, PF, D, Shape> {
#[inline]
pub const fn new(value: [PF; D]) -> Self {
Self {
value,
_phantom: PhantomData,
}
}
}
impl<F: Field, A: Algebra<F>, const D: usize, Shape: ExtensionShape> Default
for ExtField<F, D, Shape, A>
{
#[inline]
fn default() -> Self {
Self::new(core::array::from_fn(|_| A::ZERO))
}
}
impl<F: Field, A: Algebra<F>, const D: usize, Shape: ExtensionShape> From<A>
for ExtField<F, D, Shape, A>
{
#[inline]
fn from(x: A) -> Self {
Self::new(crate::field_to_array(x))
}
}
impl<F, A, const D: usize, Shape: ExtensionShape> From<[A; D]> for ExtField<F, D, Shape, A> {
#[inline]
fn from(x: [A; D]) -> Self {
Self::new(x)
}
}
impl<F, const D: usize, Shape> crate::Packable for ExtField<F, D, Shape>
where
F: Field + ExtensionAlgebra<F, D, Shape>,
Shape: ExtensionShape + Copy + Eq + core::hash::Hash + Send + Sync,
{
}
impl<F, A: Algebra<F>, const D: usize, Shape: ExtensionShape + Clone> crate::BasedVectorSpace<A>
for ExtField<F, D, Shape, A>
where
F: Field + ExtensionAlgebra<F, D, Shape>,
{
const DIMENSION: usize = D;
#[inline]
fn as_basis_coefficients_slice(&self) -> &[A] {
&self.value
}
#[inline]
fn from_basis_coefficients_fn<Fn: FnMut(usize) -> A>(f: Fn) -> Self {
Self::new(core::array::from_fn(f))
}
#[inline]
fn from_basis_coefficients_iter<I: ExactSizeIterator<Item = A>>(mut iter: I) -> Option<Self> {
(iter.len() == D).then(|| Self::new(core::array::from_fn(|_| iter.next().unwrap())))
}
#[inline]
fn flatten_to_base(vec: Vec<Self>) -> Vec<A> {
unsafe { p3_util::flatten_to_base::<A, Self>(vec) }
}
#[inline]
fn reconstitute_from_base(vec: Vec<A>) -> Vec<Self> {
unsafe { p3_util::reconstitute_from_base::<A, Self>(vec) }
}
}
impl<F, const D: usize, Shape: ExtensionShape> rand::distr::Distribution<ExtField<F, D, Shape>>
for rand::distr::StandardUniform
where
F: Field + ExtensionAlgebra<F, D, Shape>,
Self: rand::distr::Distribution<F>,
{
#[inline]
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> ExtField<F, D, Shape> {
ExtField::new(core::array::from_fn(|_| self.sample(rng)))
}
}
pub trait ExtensionAlgebra<F: Field, const D: usize, Shape: ExtensionShape>: Algebra<F> {
fn ext_mul(a: &[Self; D], b: &[Self; D], res: &mut [Self; D]);
#[inline]
fn ext_square(a: &[Self; D], res: &mut [Self; D]) {
Self::ext_mul(a, a, res);
}
#[inline]
#[must_use]
fn ext_add(a: &[Self; D], b: &[Self; D]) -> [Self; D] {
vector_add(a, b)
}
#[inline]
#[must_use]
fn ext_sub(a: &[Self; D], b: &[Self; D]) -> [Self; D] {
vector_sub(a, b)
}
#[inline]
#[must_use]
fn ext_base_mul(lhs: [Self; D], rhs: Self) -> [Self; D] {
lhs.map(|x| x * rhs.dup())
}
}
pub trait BinomiallyExtendable<const D: usize>:
Field + ExtensionAlgebra<Self, D, Binomial<Self>>
{
const W: Self;
const DTH_ROOT: Self;
const EXT_GENERATOR: [Self; D];
}
pub trait HasFrobenius<F: Field>: ExtensionField<F> {
#[must_use]
fn frobenius(&self) -> Self;
#[must_use]
fn repeated_frobenius(&self, count: usize) -> Self;
#[must_use]
fn pseudo_inv(&self) -> Self;
#[must_use]
fn galois_orbit(self) -> Vec<Self> {
iter::successors(Some(self), |x| Some(x.frobenius()))
.take(Self::DIMENSION)
.collect()
}
}
pub trait HasTwoAdicBinomialExtension<const D: usize>: BinomiallyExtendable<D> {
const EXT_TWO_ADICITY: usize;
#[must_use]
fn ext_two_adic_generator(bits: usize) -> [Self; D];
}
pub trait CubicTrinomialExtendable: Field + ExtensionAlgebra<Self, 3, CubicTrinomial> {
const FROBENIUS_MATRIX: [[Self; 3]; 3];
const EXT_GENERATOR: [Self; 3];
}
pub trait HasTwoAdicCubicExtension: CubicTrinomialExtendable {
const EXT_TWO_ADICITY: usize;
#[must_use]
fn ext_two_adic_generator(bits: usize) -> [Self; 3];
}
pub trait QuinticTrinomialExtendable: Field + ExtensionAlgebra<Self, 5, QuinticTrinomial> {
const FROBENIUS_COEFFS: [[Self; 5]; 4];
const EXT_GENERATOR: [Self; 5];
}
pub trait HasTwoAdicQuinticExtension: QuinticTrinomialExtendable {
const EXT_TWO_ADICITY: usize;
#[must_use]
fn ext_two_adic_generator(bits: usize) -> [Self; 5];
}