p3_field/
array.rs

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)] // Needed to make `transmute`s safe.
10#[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}