1use core::array;
2use core::iter::{Product, Sum};
3use core::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign};
4
5use crate::batch_inverse::batch_multiplicative_inverse_general;
6use crate::{Algebra, Field, PackedValue, PrimeCharacteristicRing};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9#[repr(transparent)] #[must_use]
11pub struct FieldArray<F: Field, const N: usize>(pub [F; N]);
12
13impl<F: Field, const N: usize> FieldArray<F, N> {
14 pub(crate) fn inverse(&self) -> Self {
15 let mut result = Self::default();
16 batch_multiplicative_inverse_general(&self.0, &mut result.0, |x| x.inverse());
17 result
18 }
19}
20
21impl<F: Field, const N: usize> Default for FieldArray<F, N> {
22 fn default() -> Self {
23 Self::ZERO
24 }
25}
26
27impl<F: Field, const N: usize> From<F> for FieldArray<F, N> {
28 fn from(val: F) -> Self {
29 [val; N].into()
30 }
31}
32
33impl<F: Field, const N: usize> From<[F; N]> for FieldArray<F, N> {
34 fn from(arr: [F; N]) -> Self {
35 Self(arr)
36 }
37}
38
39impl<F: Field, const N: usize> PrimeCharacteristicRing for FieldArray<F, N> {
40 type PrimeSubfield = F::PrimeSubfield;
41
42 const ZERO: Self = Self([F::ZERO; N]);
43 const ONE: Self = Self([F::ONE; N]);
44 const TWO: Self = Self([F::TWO; N]);
45 const NEG_ONE: Self = Self([F::NEG_ONE; N]);
46
47 #[inline]
48 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
49 F::from_prime_subfield(f).into()
50 }
51
52 #[inline]
53 fn halve(&self) -> Self {
54 Self(self.0.map(|x| x.halve()))
55 }
56}
57
58impl<F: Field, const N: usize> Algebra<F> for FieldArray<F, N> {}
59
60unsafe impl<F: Field, const N: usize> PackedValue for FieldArray<F, N> {
61 type Value = F;
62
63 const WIDTH: usize = N;
64
65 fn from_slice(slice: &[Self::Value]) -> &Self {
66 assert_eq!(slice.len(), Self::WIDTH);
67 unsafe { &*slice.as_ptr().cast() }
68 }
69
70 fn from_slice_mut(slice: &mut [Self::Value]) -> &mut Self {
71 assert_eq!(slice.len(), Self::WIDTH);
72 unsafe { &mut *slice.as_mut_ptr().cast() }
73 }
74
75 fn from_fn<Fn>(f: Fn) -> Self
76 where
77 Fn: FnMut(usize) -> Self::Value,
78 {
79 Self(array::from_fn(f))
80 }
81
82 fn as_slice(&self) -> &[Self::Value] {
83 &self.0
84 }
85
86 fn as_slice_mut(&mut self) -> &mut [Self::Value] {
87 &mut self.0
88 }
89}
90
91impl<F: Field, const N: usize> Add for FieldArray<F, N> {
92 type Output = Self;
93
94 #[inline]
95 fn add(self, rhs: Self) -> Self::Output {
96 array::from_fn(|i| self.0[i] + rhs.0[i]).into()
97 }
98}
99
100impl<F: Field, const N: usize> Add<F> for FieldArray<F, N> {
101 type Output = Self;
102
103 #[inline]
104 fn add(self, rhs: F) -> Self::Output {
105 self.0.map(|x| x + rhs).into()
106 }
107}
108
109impl<F: Field, const N: usize> AddAssign for FieldArray<F, N> {
110 #[inline]
111 fn add_assign(&mut self, rhs: Self) {
112 self.0.iter_mut().zip(rhs.0).for_each(|(x, y)| *x += y);
113 }
114}
115
116impl<F: Field, const N: usize> AddAssign<F> for FieldArray<F, N> {
117 #[inline]
118 fn add_assign(&mut self, rhs: F) {
119 self.0.iter_mut().for_each(|x| *x += rhs);
120 }
121}
122
123impl<F: Field, const N: usize> Sub for FieldArray<F, N> {
124 type Output = Self;
125
126 #[inline]
127 fn sub(self, rhs: Self) -> Self::Output {
128 array::from_fn(|i| self.0[i] - rhs.0[i]).into()
129 }
130}
131
132impl<F: Field, const N: usize> Sub<F> for FieldArray<F, N> {
133 type Output = Self;
134
135 #[inline]
136 fn sub(self, rhs: F) -> Self::Output {
137 self.0.map(|x| x - rhs).into()
138 }
139}
140
141impl<F: Field, const N: usize> SubAssign for FieldArray<F, N> {
142 #[inline]
143 fn sub_assign(&mut self, rhs: Self) {
144 self.0.iter_mut().zip(rhs.0).for_each(|(x, y)| *x -= y);
145 }
146}
147
148impl<F: Field, const N: usize> SubAssign<F> for FieldArray<F, N> {
149 #[inline]
150 fn sub_assign(&mut self, rhs: F) {
151 self.0.iter_mut().for_each(|x| *x -= rhs);
152 }
153}
154
155impl<F: Field, const N: usize> Neg for FieldArray<F, N> {
156 type Output = Self;
157
158 #[inline]
159 fn neg(self) -> Self::Output {
160 self.0.map(|x| -x).into()
161 }
162}
163
164impl<F: Field, const N: usize> Mul for FieldArray<F, N> {
165 type Output = Self;
166
167 #[inline]
168 fn mul(self, rhs: Self) -> Self::Output {
169 array::from_fn(|i| self.0[i] * rhs.0[i]).into()
170 }
171}
172
173impl<F: Field, const N: usize> Mul<F> for FieldArray<F, N> {
174 type Output = Self;
175
176 #[inline]
177 fn mul(self, rhs: F) -> Self::Output {
178 self.0.map(|x| x * rhs).into()
179 }
180}
181
182impl<F: Field, const N: usize> MulAssign for FieldArray<F, N> {
183 #[inline]
184 fn mul_assign(&mut self, rhs: Self) {
185 self.0.iter_mut().zip(rhs.0).for_each(|(x, y)| *x *= y);
186 }
187}
188
189impl<F: Field, const N: usize> MulAssign<F> for FieldArray<F, N> {
190 #[inline]
191 fn mul_assign(&mut self, rhs: F) {
192 self.0.iter_mut().for_each(|x| *x *= rhs);
193 }
194}
195
196impl<F: Field, const N: usize> Div<F> for FieldArray<F, N> {
197 type Output = Self;
198
199 #[allow(clippy::suspicious_arithmetic_impl)]
200 #[inline]
201 fn div(self, rhs: F) -> Self::Output {
202 let rhs_inv = rhs.inverse();
203 self * rhs_inv
204 }
205}
206
207impl<F: Field, const N: usize> Sum for FieldArray<F, N> {
208 #[inline]
209 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
210 iter.reduce(|lhs, rhs| lhs + rhs).unwrap_or(Self::ZERO)
211 }
212}
213
214impl<F: Field, const N: usize> Product for FieldArray<F, N> {
215 #[inline]
216 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
217 iter.reduce(|lhs, rhs| lhs * rhs).unwrap_or(Self::ONE)
218 }
219}