use crate::{
core::{
actually_used_field::ActuallyUsedField,
circuits::{
arithmetic::PowCircuit,
boolean::{boolean_array::BooleanArray, boolean_value::BooleanValue, byte::Byte},
traits::arithmetic_circuit::ArithmeticCircuit,
},
global_value::value::FieldValue,
},
traits::{FromF25519, Invert, Pow, Random, Reveal, ToLeBytes, WithBooleanBounds},
utils::{
field::{BaseField, ScalarField},
number::Number,
},
};
use num_traits::Zero;
use std::ops::{Add, Index, Mul, Neg, Sub};
#[derive(Debug, Clone, Copy)]
pub struct FieldArray<const N: usize, F: ActuallyUsedField>([FieldValue<F>; N]);
impl<const N: usize, F: ActuallyUsedField> IntoIterator for FieldArray<N, F> {
type Item = FieldValue<F>;
type IntoIter = <[FieldValue<F>; N] as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<const N: usize, F: ActuallyUsedField> Index<usize> for FieldArray<N, F> {
type Output = FieldValue<F>;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl<const N: usize, F: ActuallyUsedField> Add for FieldArray<N, F> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(
self.into_iter()
.zip(rhs)
.map(|(val_lhs, val_rhs)| val_lhs + val_rhs)
.collect::<Vec<FieldValue<F>>>()
.try_into()
.unwrap_or_else(|v: Vec<FieldValue<F>>| {
panic!("Expected a Vec of length {} (found {})", N, v.len())
}),
)
}
}
impl<const N: usize, F: ActuallyUsedField> Sub for FieldArray<N, F> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(
self.into_iter()
.zip(rhs)
.map(|(val_lhs, val_rhs)| val_lhs - val_rhs)
.collect::<Vec<FieldValue<F>>>()
.try_into()
.unwrap_or_else(|v: Vec<FieldValue<F>>| {
panic!("Expected a Vec of length {} (found {})", N, v.len())
}),
)
}
}
impl<const N: usize, F: ActuallyUsedField> Mul for FieldArray<N, F> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(
self.into_iter()
.zip(rhs)
.map(|(val_lhs, val_rhs)| val_lhs * val_rhs)
.collect::<Vec<FieldValue<F>>>()
.try_into()
.unwrap_or_else(|v: Vec<FieldValue<F>>| {
panic!("Expected a Vec of length {} (found {})", N, v.len())
}),
)
}
}
impl<const N: usize, F: ActuallyUsedField> Neg for FieldArray<N, F> {
type Output = Self;
fn neg(self) -> Self::Output {
Self(self.0.map(|val| -val))
}
}
impl<const N: usize, F: ActuallyUsedField> Mul<F> for FieldArray<N, F> {
type Output = Self;
fn mul(self, rhs: F) -> Self::Output {
Self(
self.into_iter()
.map(|val| val * rhs)
.collect::<Vec<FieldValue<F>>>()
.try_into()
.unwrap_or_else(|v: Vec<FieldValue<F>>| {
panic!("Expected a Vec of length {} (found {})", N, v.len())
}),
)
}
}
impl<const N: usize, F: ActuallyUsedField> Zero for FieldArray<N, F> {
fn zero() -> Self {
Self::from(0)
}
fn is_zero(&self) -> bool {
self.into_iter()
.map(|val| val.is_zero())
.reduce(|a, b| a & b)
.unwrap()
}
}
impl<const N: usize, F: ActuallyUsedField> Pow for FieldArray<N, F> {
fn pow(self, e: &Number, is_expected_non_zero: bool) -> Self {
let e = e % (F::modulus() - 1);
let pow_circuit = PowCircuit::new(e, is_expected_non_zero);
Self(self.0.map(|val| pow_circuit.run(vec![val])[0]))
}
}
impl<const N: usize, F: ActuallyUsedField> Invert for FieldArray<N, F> {
fn invert(self, is_expected_non_zero: bool) -> Self {
Self(self.0.map(|val| val.invert(is_expected_non_zero)))
}
}
impl<const N: usize, F: ActuallyUsedField> Reveal for FieldArray<N, F> {
fn reveal(self) -> Self {
Self(self.0.map(|val| val.reveal()))
}
}
impl<const N: usize, F: ActuallyUsedField> Random for FieldArray<N, F> {
fn random() -> Self {
Self(
(0..N)
.map(|_| FieldValue::<F>::random())
.collect::<Vec<FieldValue<F>>>()
.try_into()
.unwrap_or_else(|v: Vec<FieldValue<F>>| {
panic!("Expected a Vec of length {} (found {})", N, v.len())
}),
)
}
}
impl<const N: usize, F: ActuallyUsedField> WithBooleanBounds for FieldArray<N, F> {
fn with_boolean_bounds(&self) -> Self {
todo!()
}
}
impl<const N: usize, F: ActuallyUsedField> From<[FieldValue<F>; N]> for FieldArray<N, F> {
fn from(value: [FieldValue<F>; N]) -> Self {
Self(value)
}
}
impl<const N: usize, F: ActuallyUsedField> From<FieldArray<N, F>> for [FieldValue<F>; N] {
fn from(value: FieldArray<N, F>) -> Self {
value.0
}
}
impl<const N: usize, F: ActuallyUsedField> From<i32> for FieldArray<N, F> {
fn from(value: i32) -> Self {
Self([FieldValue::<F>::from(value); N])
}
}
impl<const N: usize, F: ActuallyUsedField> From<Number> for FieldArray<N, F> {
fn from(value: Number) -> Self {
Self([FieldValue::<F>::from(value); N])
}
}
impl<const N: usize, F: ActuallyUsedField> From<F> for FieldArray<N, F> {
fn from(value: F) -> Self {
Self([FieldValue::from(value); N])
}
}
impl<const N: usize, F: ActuallyUsedField> From<FieldValue<F>> for FieldArray<N, F> {
fn from(value: FieldValue<F>) -> Self {
Self([value; N])
}
}
impl<const N: usize, F: ActuallyUsedField> From<BooleanArray<N>> for FieldArray<N, F> {
fn from(value: BooleanArray<N>) -> Self {
Self(
value
.into_iter()
.map(FieldValue::from)
.collect::<Vec<FieldValue<F>>>()
.try_into()
.unwrap_or_else(|v: Vec<FieldValue<F>>| {
panic!("Expected a Vec of length {} (found {})", N, v.len())
}),
)
}
}
impl<const N: usize, F: ActuallyUsedField> ToLeBytes for FieldArray<N, F> {
type BooleanOutput = BooleanArray<N>;
fn to_le_bytes(self) -> [Byte<Self::BooleanOutput>; 32] {
let bytes_vec = self
.0
.into_iter()
.map(|val| val.to_le_bytes())
.collect::<Vec<[Byte<BooleanValue>; 32]>>();
(0..32)
.map(|i| {
Byte::new(
(0..8)
.map(|j| {
BooleanArray::from(
TryInto::<[BooleanValue; N]>::try_into(
bytes_vec
.iter()
.map(|bytes| bytes[i].get_bits()[j])
.collect::<Vec<BooleanValue>>(),
)
.unwrap_or_else(
|v: Vec<BooleanValue>| {
panic!("Expected a Vec of length {} (found {})", N, v.len())
},
),
)
})
.collect::<Vec<BooleanArray<N>>>()
.try_into()
.unwrap_or_else(|v: Vec<BooleanArray<N>>| {
panic!("Expected a Vec of length 8 (found {})", v.len())
}),
)
})
.collect::<Vec<Byte<Self::BooleanOutput>>>()
.try_into()
.unwrap_or_else(|v: Vec<Byte<Self::BooleanOutput>>| {
panic!("Expected a Vec of length 32 (found {})", v.len())
})
}
}
impl<const N: usize> FromF25519<FieldArray<N, BaseField>> for FieldArray<N, BaseField> {
fn from_F25519(value: FieldArray<N, BaseField>) -> Vec<FieldArray<N, BaseField>> {
vec![value]
}
}
impl<const N: usize> FromF25519<FieldArray<N, BaseField>> for FieldArray<N, ScalarField> {
fn from_F25519(_value: FieldArray<N, BaseField>) -> Vec<FieldArray<N, ScalarField>> {
todo!();
}
}