use std::fmt::Debug;
use std::ops::{Div, Index, IndexMut};
use std::slice::Iter;
use serde::de::DeserializeOwned;
use serde::Serialize;
use typenum::Unsigned;
use typenum::{U2, U4};
use generic_array::sequence::GenericSequence;
use generic_array::{ArrayLength, GenericArray};
use num::BigUint;
use p3_field::Field;
use crate::air::Polynomial;
use crate::utils::ec::utils::biguint_from_limbs;
pub const NB_BITS_PER_LIMB: usize = 8;
#[derive(Debug, Clone)]
pub struct Limbs<T, N: ArrayLength>(pub GenericArray<T, N>);
pub trait FieldParameters:
Send + Sync + Copy + 'static + Debug + Serialize + DeserializeOwned + NumLimbs
{
const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB;
const NB_LIMBS: usize = Self::Limbs::USIZE;
const NB_WITNESS_LIMBS: usize = Self::Witness::USIZE;
const WITNESS_OFFSET: usize;
const MODULUS: &'static [u8];
fn modulus() -> BigUint {
biguint_from_limbs(Self::MODULUS)
}
fn nb_bits() -> usize {
Self::NB_BITS_PER_LIMB * Self::NB_LIMBS
}
fn modulus_field_iter<F: Field>() -> impl Iterator<Item = F> {
Self::MODULUS
.iter()
.map(|x| F::from_canonical_u8(*x))
.take(Self::NB_LIMBS)
}
fn to_limbs(x: &BigUint) -> Vec<u8> {
let mut bytes = x.to_bytes_le();
bytes.resize(Self::NB_LIMBS, 0u8);
bytes
}
fn to_limbs_field_vec<E: From<F>, F: Field>(x: &BigUint) -> Vec<E> {
Self::to_limbs(x)
.into_iter()
.map(|x| F::from_canonical_u8(x).into())
.collect::<Vec<_>>()
}
fn to_limbs_field<E: From<F>, F: Field>(x: &BigUint) -> Limbs<E, Self::Limbs> {
limbs_from_vec(Self::to_limbs_field_vec(x))
}
}
pub fn limbs_from_vec<E: From<F>, N: ArrayLength, F: Field>(limbs: Vec<F>) -> Limbs<E, N> {
debug_assert_eq!(limbs.len(), N::USIZE);
let mut result = GenericArray::<E, N>::generate(|_i| F::zero().into());
for (i, limb) in limbs.into_iter().enumerate() {
result[i] = limb.into();
}
Limbs(result)
}
pub trait NumLimbs: Clone + Debug {
type Limbs: ArrayLength + Debug;
type Witness: ArrayLength + Debug;
}
pub trait NumWords: Clone + Debug {
type WordsFieldElement: ArrayLength + Debug;
type WordsCurvePoint: ArrayLength + Debug;
}
impl<N: NumLimbs> NumWords for N
where
N::Limbs: Div<U4>,
N::Limbs: Div<U2>,
<N::Limbs as Div<U4>>::Output: ArrayLength + Debug,
<N::Limbs as Div<U2>>::Output: ArrayLength + Debug,
{
type WordsFieldElement = <N::Limbs as Div<U4>>::Output;
type WordsCurvePoint = <N::Limbs as Div<U2>>::Output;
}
impl<T: Copy, N: ArrayLength> Copy for Limbs<T, N> where N::ArrayType<T>: Copy {}
impl<T, N: ArrayLength> Default for Limbs<T, N>
where
T: Default + Copy,
{
fn default() -> Self {
Self(GenericArray::default())
}
}
impl<T, N: ArrayLength> Index<usize> for Limbs<T, N> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl<T, N: ArrayLength> IndexMut<usize> for Limbs<T, N> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
impl<T, N: ArrayLength> IntoIterator for Limbs<T, N> {
type Item = T;
type IntoIter = <GenericArray<T, N> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<Var: Into<Expr> + Clone, N: ArrayLength, Expr: Clone> From<Limbs<Var, N>>
for Polynomial<Expr>
{
fn from(value: Limbs<Var, N>) -> Self {
Polynomial::from_coefficients(&value.0.into_iter().map(|x| x.into()).collect::<Vec<_>>())
}
}
impl<'a, Var: Into<Expr> + Clone, Expr: Clone> From<Iter<'a, Var>> for Polynomial<Expr> {
fn from(value: Iter<'a, Var>) -> Self {
Polynomial::from_coefficients(&value.map(|x| (*x).clone().into()).collect::<Vec<_>>())
}
}
impl<T: Debug + Default + Clone, N: ArrayLength> From<Polynomial<T>> for Limbs<T, N> {
fn from(value: Polynomial<T>) -> Self {
let inner = value.as_coefficients().try_into().unwrap();
Self(inner)
}
}
impl<'a, T: Debug + Default + Clone, N: ArrayLength> From<Iter<'a, T>> for Limbs<T, N> {
fn from(value: Iter<'a, T>) -> Self {
let vec: Vec<T> = value.cloned().collect();
let inner = vec.try_into().unwrap();
Self(inner)
}
}
#[cfg(test)]
mod tests {
use crate::operations::field::params::FieldParameters;
use num::BigUint;
use crate::utils::ec::edwards::ed25519::Ed25519BaseField;
#[test]
fn test_modulus() {
let array_modulus = BigUint::from_bytes_le(Ed25519BaseField::MODULUS);
let func_modulus = Ed25519BaseField::modulus();
assert_eq!(
array_modulus, func_modulus,
"MODULUS array does not match the modulus() function output."
);
}
}