Skip to main content

p3_field/
field.rs

1use alloc::vec;
2use alloc::vec::Vec;
3use core::fmt::{Debug, Display};
4use core::hash::Hash;
5use core::iter::{Product, Sum, zip};
6use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7use core::{array, slice};
8
9use num_bigint::BigUint;
10use p3_maybe_rayon::prelude::*;
11use p3_util::{flatten_to_base, iter_array_chunks_padded};
12use serde::Serialize;
13use serde::de::DeserializeOwned;
14
15use crate::exponentiation::bits_u64;
16use crate::integers::{QuotientMap, from_integer_types};
17use crate::packed::PackedField;
18use crate::{Dup, Packable, PackedFieldExtension, PackedValue};
19
20/// A commutative ring, `R`, with prime characteristic, `p`.
21///
22/// This permits elements like:
23/// - A single finite field element.
24/// - A symbolic expression which would evaluate to a field element.
25/// - An array of finite field elements.
26/// - A polynomial with coefficients in a finite field.
27///
28/// ### Mathematical Description
29///
30/// Mathematically, a commutative ring is a set of objects which supports an addition-like
31/// like operation, `+`, and a multiplication-like operation `*`.
32///
33/// Let `x, y, z` denote arbitrary elements of the set.
34///
35/// Then, an operation is addition-like if it satisfies the following properties:
36/// - Commutativity => `x + y = y + x`
37/// - Associativity => `x + (y + z) = (x + y) + z`
38/// - Unit => There exists an identity element `ZERO` satisfying `x + ZERO = x`.
39/// - Inverses => For every `x` there exists a unique inverse `(-x)` satisfying `x + (-x) = ZERO`
40///
41/// Similarly, an operation is multiplication-like if it satisfies the following properties:
42/// - Commutativity => `x * y = y * x`
43/// - Associativity => `x * (y * z) = (x * y) * z`
44/// - Unit => There exists an identity element `ONE` satisfying `x * ONE = x`.
45/// - Distributivity => The two operations `+` and `*` must together satisfy `x * (y + z) = (x * y) + (x * z)`
46///
47/// Unlike in the addition case, we do not require inverses to exist with respect to `*`.
48///
49/// The simplest examples of commutative rings are the integers (`ℤ`), and the integers mod `N` (`ℤ/N`).
50///
51/// The characteristic of a ring is the smallest positive integer `r` such that `0 = r . 1 = 1 + 1 + ... + 1 (r times)`.
52/// For example, the characteristic of the modulo ring `ℤ/N` is `N`.
53///
54/// Rings with prime characteristic are particularly special due to their close relationship with finite fields.
55pub trait PrimeCharacteristicRing:
56    Sized
57    + Default
58    + Dup
59    + Add<Output = Self>
60    + AddAssign
61    + Sub<Output = Self>
62    + SubAssign
63    + Neg<Output = Self>
64    + Mul<Output = Self>
65    + MulAssign
66    + Sum
67    + Product
68    + Debug
69{
70    /// The field `ℤ/p` where the characteristic of this ring is p.
71    type PrimeSubfield: PrimeField;
72
73    /// The additive identity of the ring.
74    ///
75    /// For every element `a` in the ring we require the following properties:
76    ///
77    /// `a + ZERO = ZERO + a = a,`
78    ///
79    /// `a + (-a) = (-a) + a = ZERO.`
80    const ZERO: Self;
81
82    /// The multiplicative identity of the ring.
83    ///
84    /// For every element `a` in the ring we require the following property:
85    ///
86    /// `a*ONE = ONE*a = a.`
87    const ONE: Self;
88
89    /// The element in the ring given by `ONE + ONE`.
90    ///
91    /// This is provided as a convenience as `TWO` occurs regularly in
92    /// the proving system. This also is slightly faster than computing
93    /// it via addition. Note that multiplication by `TWO` is discouraged.
94    /// Instead of `a * TWO` use `a.double()` which will be faster.
95    ///
96    /// If the field has characteristic 2 this is equal to ZERO.
97    const TWO: Self;
98
99    /// The element in the ring given by `-ONE`.
100    ///
101    /// This is provided as a convenience as `NEG_ONE` occurs regularly in
102    /// the proving system. This also is slightly faster than computing
103    /// it via negation. Note that where possible `NEG_ONE` should be absorbed
104    /// into mathematical operations. For example `a - b` will be faster
105    /// than `a + NEG_ONE * b` and similarly `(-b)` is faster than `NEG_ONE * b`.
106    ///
107    /// If the field has characteristic 2 this is equal to ONE.
108    const NEG_ONE: Self;
109
110    /// Embed an element of the prime field `ℤ/p` into the ring `R`.
111    ///
112    /// Given any element `[r] ∈ ℤ/p`, represented by an integer `r` between `0` and `p - 1`
113    /// `from_prime_subfield([r])` will be equal to:
114    ///
115    /// `Self::ONE + ... + Self::ONE (r times)`
116    #[must_use]
117    fn from_prime_subfield(f: Self::PrimeSubfield) -> Self;
118
119    /// Return `Self::ONE` if `b` is `true` and `Self::ZERO` if `b` is `false`.
120    #[must_use]
121    #[inline(always)]
122    fn from_bool(b: bool) -> Self {
123        // Some rings might reimplement this to avoid the branch.
124        if b { Self::ONE } else { Self::ZERO }
125    }
126
127    from_integer_types!(
128        u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
129    );
130
131    /// The elementary function `double(a) = 2*a`.
132    ///
133    /// This function should be preferred over calling `a + a` or `TWO * a` as a faster implementation may be available for some rings.
134    /// If the field has characteristic 2 then this returns 0.
135    #[must_use]
136    #[inline(always)]
137    fn double(&self) -> Self {
138        self.dup() + self.dup()
139    }
140
141    /// The elementary function `halve(a) = a/2`.
142    ///
143    /// # Panics
144    /// The function will panic if the field has characteristic 2.
145    #[must_use]
146    #[inline]
147    fn halve(&self) -> Self {
148        // This must be overwritten by PrimeField implementations as this definition
149        // is circular when PrimeSubfield = Self. It should also be overwritten by
150        // most rings to avoid the multiplication.
151        let half = Self::from_prime_subfield(Self::PrimeSubfield::ONE.halve());
152        self.dup() * half
153    }
154
155    /// The elementary function `square(a) = a^2`.
156    ///
157    /// This function should be preferred over calling `a * a`, as a faster implementation may be available for some rings.
158    #[must_use]
159    #[inline(always)]
160    fn square(&self) -> Self {
161        self.dup() * self.dup()
162    }
163
164    /// The elementary function `cube(a) = a^3`.
165    ///
166    /// This function should be preferred over calling `a * a * a`, as a faster implementation may be available for some rings.
167    #[must_use]
168    #[inline(always)]
169    fn cube(&self) -> Self {
170        self.square() * self.dup()
171    }
172
173    /// Computes the arithmetic generalization of boolean `xor`.
174    ///
175    /// For boolean inputs, `x ^ y = x + y - 2 xy`.
176    #[must_use]
177    #[inline(always)]
178    fn xor(&self, y: &Self) -> Self {
179        self.dup() + y.dup() - self.dup() * y.dup().double()
180    }
181
182    /// Computes the arithmetic generalization of a triple `xor`.
183    ///
184    /// For boolean inputs `x ^ y ^ z = x + y + z - 2(xy + xz + yz) + 4xyz`.
185    #[must_use]
186    #[inline(always)]
187    fn xor3(&self, y: &Self, z: &Self) -> Self {
188        self.xor(y).xor(z)
189    }
190
191    /// Computes the arithmetic generalization of `andnot`.
192    ///
193    /// For boolean inputs `(!x) & y = (1 - x)y`.
194    #[must_use]
195    #[inline(always)]
196    fn andn(&self, y: &Self) -> Self {
197        (Self::ONE - self.dup()) * y.dup()
198    }
199
200    /// The vanishing polynomial for boolean values: `x * (x - 1)`.
201    ///
202    /// This is a polynomial of degree `2` that evaluates to `0` if the input is `0` or `1`.
203    /// If our space is a field, then this will be nonzero on all other inputs.
204    #[must_use]
205    #[inline(always)]
206    fn bool_check(&self) -> Self {
207        // Note: We could delegate to `andn`, but to maintain backwards
208        // compatible AIR definitions, we stick with `x * (x - 1)` here.
209        self.dup() * (self.dup() - Self::ONE)
210    }
211
212    /// Exponentiation by a `u64` power.
213    ///
214    /// This uses the standard square and multiply approach.
215    /// For specific powers regularly used and known in advance,
216    /// this will be slower than custom addition chain exponentiation.
217    #[must_use]
218    #[inline]
219    fn exp_u64(&self, power: u64) -> Self {
220        let mut current = self.dup();
221        let mut product = Self::ONE;
222
223        for j in 0..bits_u64(power) {
224            if (power >> j) & 1 != 0 {
225                product *= current.dup();
226            }
227            current = current.square();
228        }
229        product
230    }
231
232    /// Exponentiation by a small constant power.
233    ///
234    /// For a collection of small values we implement custom multiplication chain circuits which can be faster than the
235    /// simpler square and multiply approach.
236    ///
237    /// For large values this defaults back to `self.exp_u64`.
238    #[must_use]
239    #[inline(always)]
240    fn exp_const_u64<const POWER: u64>(&self) -> Self {
241        match POWER {
242            0 => Self::ONE,
243            1 => self.dup(),
244            2 => self.square(),
245            3 => self.cube(),
246            4 => self.square().square(),
247            5 => self.square().square() * self.dup(),
248            6 => self.square().cube(),
249            7 => {
250                let x2 = self.square();
251                let x3 = x2.dup() * self.dup();
252                let x4 = x2.square();
253                x3 * x4
254            }
255            _ => self.exp_u64(POWER),
256        }
257    }
258
259    /// The elementary function `exp_power_of_2(a, power_log) = a^{2^power_log}`.
260    ///
261    /// Computed via repeated squaring.
262    #[must_use]
263    #[inline]
264    fn exp_power_of_2(&self, power_log: usize) -> Self {
265        let mut res = self.dup();
266        for _ in 0..power_log {
267            res = res.square();
268        }
269        res
270    }
271
272    /// The elementary function `mul_2exp_u64(a, exp) = a * 2^{exp}`.
273    ///
274    /// Here `2^{exp}` is computed using the square and multiply approach.
275    #[must_use]
276    #[inline]
277    fn mul_2exp_u64(&self, exp: u64) -> Self {
278        // Some rings might want to reimplement this to avoid the
279        // exponentiations (and potentially even the multiplication).
280        self.dup() * Self::TWO.exp_u64(exp)
281    }
282
283    /// Divide by a given power of two. `div_2exp_u64(a, exp) = a/2^exp`
284    ///
285    /// # Panics
286    /// The function will panic if the field has characteristic 2.
287    #[must_use]
288    #[inline]
289    fn div_2exp_u64(&self, exp: u64) -> Self {
290        // Some rings might want to reimplement this to avoid the
291        // exponentiations (and potentially even the multiplication).
292        self.dup() * Self::from_prime_subfield(Self::PrimeSubfield::ONE.halve().exp_u64(exp))
293    }
294
295    /// Construct an iterator which returns powers of `self`: `self^0, self^1, self^2, ...`.
296    #[must_use]
297    #[inline]
298    fn powers(&self) -> Powers<Self> {
299        self.shifted_powers(Self::ONE)
300    }
301
302    /// Construct an iterator which returns powers of `self` shifted by `start`: `start, start*self^1, start*self^2, ...`.
303    #[must_use]
304    #[inline]
305    fn shifted_powers(&self, start: Self) -> Powers<Self> {
306        Powers {
307            base: self.dup(),
308            current: start,
309        }
310    }
311
312    /// Compute the dot product of two vectors.
313    #[must_use]
314    #[inline]
315    fn dot_product<const N: usize>(u: &[Self; N], v: &[Self; N]) -> Self {
316        u.iter().zip(v).map(|(x, y)| x.dup() * y.dup()).sum()
317    }
318
319    /// Compute the sum of a slice of elements whose length is a compile time constant.
320    ///
321    /// The rust compiler doesn't realize that add is associative
322    /// so we help it out and minimize the dependency chains by hand.
323    /// Thus while this function has the same throughput as `input.iter().sum()`,
324    /// it will usually have much lower latency.
325    ///
326    /// # Panics
327    ///
328    /// May panic if the length of the input slice is not equal to `N`.
329    #[must_use]
330    #[inline]
331    fn sum_array<const N: usize>(input: &[Self]) -> Self {
332        // It looks a little strange but using a const parameter and an assert_eq! instead of
333        // using input.len() leads to a significant performance improvement.
334        // We could make this input &[Self; N] but that would require sticking .try_into().unwrap() everywhere.
335        // Checking godbolt, the compiler seems to unroll everything anyway.
336        assert_eq!(N, input.len());
337
338        // For `N <= 8` we implement a tree sum structure and for `N > 8` we break the input into
339        // chunks of `8`, perform a tree sum on each chunk and sum the results. The parameter `8`
340        // was determined experimentally by testing the speed of the poseidon2 internal layer computations.
341        // This is a useful benchmark as we have a mix of summations of size 15, 23 with other work in between.
342        // I only tested this on `AVX2` though so there might be a better value for other architectures.
343        match N {
344            0 => Self::ZERO,
345            1 => input[0].dup(),
346            2 => input[0].dup() + input[1].dup(),
347            3 => input[0].dup() + input[1].dup() + input[2].dup(),
348            4 => (input[0].dup() + input[1].dup()) + (input[2].dup() + input[3].dup()),
349            5 => Self::sum_array::<4>(&input[..4]) + Self::sum_array::<1>(&input[4..]),
350            6 => Self::sum_array::<4>(&input[..4]) + Self::sum_array::<2>(&input[4..]),
351            7 => Self::sum_array::<4>(&input[..4]) + Self::sum_array::<3>(&input[4..]),
352            8 => Self::sum_array::<4>(&input[..4]) + Self::sum_array::<4>(&input[4..]),
353            _ => {
354                // We know that N > 8 here so this saves an add over the usual
355                // initialisation of acc to Self::ZERO.
356                let mut acc = Self::sum_array::<8>(&input[..8]);
357                for i in (16..=N).step_by(8) {
358                    acc += Self::sum_array::<8>(&input[(i - 8)..i]);
359                }
360                // This would be much cleaner if we could use const generic expressions but
361                // this will do for now.
362                match N & 7 {
363                    0 => acc,
364                    1 => acc + Self::sum_array::<1>(&input[(8 * (N / 8))..]),
365                    2 => acc + Self::sum_array::<2>(&input[(8 * (N / 8))..]),
366                    3 => acc + Self::sum_array::<3>(&input[(8 * (N / 8))..]),
367                    4 => acc + Self::sum_array::<4>(&input[(8 * (N / 8))..]),
368                    5 => acc + Self::sum_array::<5>(&input[(8 * (N / 8))..]),
369                    6 => acc + Self::sum_array::<6>(&input[(8 * (N / 8))..]),
370                    7 => acc + Self::sum_array::<7>(&input[(8 * (N / 8))..]),
371                    _ => unreachable!(),
372                }
373            }
374        }
375    }
376
377    /// Allocates a vector of zero elements of length `len`. Many operating systems zero pages
378    /// before assigning them to a userspace process. In that case, our process should not need to
379    /// write zeros, which would be redundant. However, the compiler may not always recognize this.
380    ///
381    /// In particular, `vec![Self::ZERO; len]` appears to result in redundant userspace zeroing.
382    /// This is the default implementation, but implementers may wish to provide their own
383    /// implementation which transmutes something like `vec![0u32; len]`.
384    #[must_use]
385    #[inline]
386    fn zero_vec(len: usize) -> Vec<Self> {
387        vec![Self::ZERO; len]
388    }
389}
390
391/// A vector space `V` over `F` with a fixed basis. Fixing the basis allows elements of `V` to be
392/// converted to and from `DIMENSION` many elements of `F` which are interpreted as basis coefficients.
393///
394/// We usually expect `F` to be a field but do not enforce this and so allow it to be just a ring.
395/// This lets every ring implement `BasedVectorSpace<Self>` and is useful in a couple of other cases.
396///
397/// ## Safety
398/// We make no guarantees about consistency of the choice of basis across different versions of Plonky3.
399/// If this choice of basis changes, the behaviour of `BasedVectorSpace` will also change. Due to this,
400/// we recommend avoiding using this trait unless absolutely necessary.
401///
402/// ### Mathematical Description
403/// Given a vector space, `A` over `F`, a basis is a set of elements `B = {b_0, ..., b_{n-1}}`
404/// in `A` such that, given any element `a`, we can find a unique set of `n` elements of `F`,
405/// `f_0, ..., f_{n - 1}` satisfying `a = f_0 b_0 + ... + f_{n - 1} b_{n - 1}`. Thus the choice
406/// of `B` gives rise to a natural linear map between the vector space `A` and the canonical
407/// `n` dimensional vector space `F^n`.
408///
409/// This allows us to map between elements of `A` and arrays of `n` elements of `F`.
410/// Clearly this map depends entirely on the choice of basis `B` which may change
411/// across versions of Plonky3.
412///
413/// The situation is slightly more complicated in cases where `F` is not a field but boils down
414/// to an identical description once we enforce that `A` is a free module over `F`.
415pub trait BasedVectorSpace<F: PrimeCharacteristicRing>: Sized {
416    /// The dimension of the vector space, i.e. the number of elements in
417    /// its basis.
418    const DIMENSION: usize;
419
420    /// Fixes a basis for the algebra `A` and uses this to
421    /// map an element of `A` to a slice of `DIMENSION` `F` elements.
422    ///
423    /// # Safety
424    ///
425    /// The value produced by this function fundamentally depends
426    /// on the choice of basis. Care must be taken
427    /// to ensure portability if these values might ever be passed to
428    /// (or rederived within) another compilation environment where a
429    /// different basis might have been used.
430    #[must_use]
431    fn as_basis_coefficients_slice(&self) -> &[F];
432
433    /// Fixes a basis for the algebra `A` and uses this to
434    /// map `DIMENSION` `F` elements to an element of `A`.
435    ///
436    /// # Safety
437    ///
438    /// The value produced by this function fundamentally depends
439    /// on the choice of basis. Care must be taken
440    /// to ensure portability if these values might ever be passed to
441    /// (or rederived within) another compilation environment where a
442    /// different basis might have been used.
443    ///
444    /// Returns `None` if the length of the slice is different to `DIMENSION`.
445    #[must_use]
446    #[inline]
447    fn from_basis_coefficients_slice(slice: &[F]) -> Option<Self> {
448        Self::from_basis_coefficients_iter(slice.iter().cloned())
449    }
450
451    /// Fixes a basis for the algebra `A` and uses this to
452    /// map `DIMENSION` `F` elements to an element of `A`. Similar
453    /// to `core:array::from_fn`, the `DIMENSION` `F` elements are
454    /// given by `Fn(0), ..., Fn(DIMENSION - 1)` called in that order.
455    ///
456    /// # Safety
457    ///
458    /// The value produced by this function fundamentally depends
459    /// on the choice of basis. Care must be taken
460    /// to ensure portability if these values might ever be passed to
461    /// (or rederived within) another compilation environment where a
462    /// different basis might have been used.
463    #[must_use]
464    fn from_basis_coefficients_fn<Fn: FnMut(usize) -> F>(f: Fn) -> Self;
465
466    /// Fixes a basis for the algebra `A` and uses this to
467    /// map `DIMENSION` `F` elements to an element of `A`.
468    ///
469    /// # Safety
470    ///
471    /// The value produced by this function fundamentally depends
472    /// on the choice of basis. Care must be taken
473    /// to ensure portability if these values might ever be passed to
474    /// (or rederived within) another compilation environment where a
475    /// different basis might have been used.
476    ///
477    /// Returns `None` if the length of the iterator is different to `DIMENSION`.
478    #[must_use]
479    fn from_basis_coefficients_iter<I: ExactSizeIterator<Item = F>>(iter: I) -> Option<Self>;
480
481    /// Given a basis for the Algebra `A`, return the i'th basis element.
482    ///
483    /// # Safety
484    ///
485    /// The value produced by this function fundamentally depends
486    /// on the choice of basis. Care must be taken
487    /// to ensure portability if these values might ever be passed to
488    /// (or rederived within) another compilation environment where a
489    /// different basis might have been used.
490    ///
491    /// Returns `None` if `i` is greater than or equal to `DIMENSION`.
492    #[must_use]
493    #[inline]
494    fn ith_basis_element(i: usize) -> Option<Self> {
495        (i < Self::DIMENSION).then(|| Self::from_basis_coefficients_fn(|j| F::from_bool(i == j)))
496    }
497
498    /// Convert from a vector of `Self` to a vector of `F` by flattening the basis coefficients.
499    ///
500    /// Depending on the `BasedVectorSpace` this may be essentially a no-op and should certainly
501    /// be reimplemented in those cases.
502    ///
503    /// # Safety
504    ///
505    /// The value produced by this function fundamentally depends
506    /// on the choice of basis. Care must be taken
507    /// to ensure portability if these values might ever be passed to
508    /// (or rederived within) another compilation environment where a
509    /// different basis might have been used.
510    #[must_use]
511    #[inline]
512    fn flatten_to_base(vec: Vec<Self>) -> Vec<F> {
513        vec.into_iter()
514            .flat_map(|x| x.as_basis_coefficients_slice().to_vec())
515            .collect()
516    }
517
518    /// Convert from a vector of `F` to a vector of `Self` by combining the basis coefficients.
519    ///
520    /// Depending on the `BasedVectorSpace` this may be essentially a no-op and should certainly
521    /// be reimplemented in those cases.
522    ///
523    /// # Panics
524    /// This will panic if the length of `vec` is not a multiple of `Self::DIMENSION`.
525    ///
526    /// # Safety
527    ///
528    /// The value produced by this function fundamentally depends
529    /// on the choice of basis. Care must be taken
530    /// to ensure portability if these values might ever be passed to
531    /// (or rederived within) another compilation environment where a
532    /// different basis might have been used.
533    #[must_use]
534    #[inline]
535    fn reconstitute_from_base(vec: Vec<F>) -> Vec<Self>
536    where
537        F: Sync,
538        Self: Send,
539    {
540        assert_eq!(vec.len() % Self::DIMENSION, 0);
541
542        vec.par_chunks_exact(Self::DIMENSION)
543            .map(|chunk| {
544                Self::from_basis_coefficients_slice(chunk)
545                    .expect("Chunk length not equal to dimension")
546            })
547            .collect()
548    }
549}
550
551/// Values that can act as sponge lanes for delimiter padding.
552///
553/// This is used by symmetric sponge adapters that need canonical `0` and `1` symbols while
554/// supporting both field/ring-based lanes and `u64`-based Keccak lanes behind one API.
555pub trait SpongePaddingValue: Copy {
556    /// The empty-lane value.
557    const PAD_ZERO: Self;
558
559    /// The delimiter value injected after the final absorbed element.
560    const PAD_ONE: Self;
561}
562
563impl<T: PrimeCharacteristicRing + Copy> SpongePaddingValue for T {
564    const PAD_ZERO: Self = Self::ZERO;
565    const PAD_ONE: Self = Self::ONE;
566}
567
568impl SpongePaddingValue for u64 {
569    const PAD_ZERO: Self = 0;
570    const PAD_ONE: Self = 1;
571}
572
573impl<const N: usize> SpongePaddingValue for [u64; N] {
574    const PAD_ZERO: Self = [0; N];
575    const PAD_ONE: Self = [1; N];
576}
577
578/// Trait for fields that support uniform bit sampling optimizations.
579pub trait UniformSamplingField {
580    /// Maximum number of bits we can sample at negligible (~1/field prime) probability of
581    /// triggering an error / requiring a resample.
582    const MAX_SINGLE_SAMPLE_BITS: usize;
583    /// An array storing the largest value `m_k` for each `k` in [0, 31], such that `m_k`
584    /// is a multiple of `2^k` and less than P. `m_k` is defined as:
585    ///
586    /// \( m_k = ⌊P / 2^k⌋ · 2^k \)
587    ///
588    /// This is used as a rejection sampling threshold (or error trigger), when sampling
589    /// random bits from uniformly sampled field elements. As long as we sample up to the `k`
590    /// least significant bits in the range [0, m_k), we sample from exactly `m_k` elements. As
591    /// `m_k` is divisible by 2^k, each of the least significant `k` bits has exactly the same
592    /// number of zeroes and ones, leading to a uniform sampling.
593    const SAMPLING_BITS_M: [u64; 64];
594}
595
596impl<F: PrimeCharacteristicRing> BasedVectorSpace<F> for F {
597    const DIMENSION: usize = 1;
598
599    #[inline]
600    fn as_basis_coefficients_slice(&self) -> &[F] {
601        slice::from_ref(self)
602    }
603
604    #[inline]
605    fn from_basis_coefficients_fn<Fn: FnMut(usize) -> F>(mut f: Fn) -> Self {
606        f(0)
607    }
608
609    #[inline]
610    fn from_basis_coefficients_iter<I: ExactSizeIterator<Item = F>>(mut iter: I) -> Option<Self> {
611        (iter.len() == 1).then(|| iter.next().unwrap()) // Unwrap will not panic as we know the length is 1.
612    }
613
614    #[inline]
615    fn flatten_to_base(vec: Vec<Self>) -> Vec<F> {
616        vec
617    }
618
619    #[inline]
620    fn reconstitute_from_base(vec: Vec<F>) -> Vec<Self> {
621        vec
622    }
623}
624
625/// A ring implements `InjectiveMonomial<N>` if the algebraic function
626/// `f(x) = x^N` is an injective map on elements of the ring.
627///
628/// We do not enforce that this map be invertible as there are useful
629/// cases such as polynomials or symbolic expressions where no inverse exists.
630///
631/// However, if the ring is a field with order `q` or an array of such field elements,
632/// then `f(x) = x^N` will be injective if and only if it is invertible and so in
633/// such cases this monomial acts as a permutation. Moreover, this will occur
634/// exactly when `N` and `q - 1` are relatively prime i.e. `gcd(N, q - 1) = 1`.
635pub trait InjectiveMonomial<const N: u64>: PrimeCharacteristicRing {
636    /// Compute `x -> x^n` for a given `n > 1` such that this
637    /// map is injective.
638    #[must_use]
639    #[inline]
640    fn injective_exp_n(&self) -> Self {
641        self.exp_const_u64::<N>()
642    }
643}
644
645/// A ring implements `PermutationMonomial<N>` if the algebraic function
646/// `f(x) = x^N` is invertible and thus acts as a permutation on elements of the ring.
647///
648/// In all cases we care about, this means that we can find another integer `K` such
649/// that `x = x^{NK}` for all elements of our ring.
650pub trait PermutationMonomial<const N: u64>: InjectiveMonomial<N> {
651    /// Compute `x -> x^K` for a given `K > 1` such that
652    /// `x^{NK} = x` for all elements `x`.
653    #[must_use]
654    fn injective_exp_root_n(&self) -> Self;
655}
656
657/// A ring `R` implements `Algebra<F>` if there is an injective homomorphism
658///  from `F` into `R`; in particular only `F::ZERO` maps to `R::ZERO`.
659///
660/// For the most part, we will usually expect `F` to be a field but there
661/// are a few cases where it is handy to allow it to just be a ring. In
662/// particular, every ring naturally implements `Algebra<Self>`.
663///
664/// ### Mathematical Description
665///
666/// Let `x` and `y` denote arbitrary elements of `F`. Then
667/// we require that our map `from` has the properties:
668/// - Preserves Identity: `from(F::ONE) = R::ONE`
669/// - Commutes with Addition: `from(x + y) = from(x) + from(y)`
670/// - Commutes with Multiplication: `from(x * y) = from(x) * from(y)`
671///
672/// Such maps are known as ring homomorphisms and are injective if the
673/// only element which maps to `R::ZERO` is `F::ZERO`.
674///
675/// The existence of this map makes `R` into an `F`-module and hence an `F`-algebra.
676/// If, additionally, `R` is a field, then this makes `R` a field extension of `F`.
677pub trait Algebra<F>:
678    PrimeCharacteristicRing
679    + From<F>
680    + Add<F, Output = Self>
681    + AddAssign<F>
682    + Sub<F, Output = Self>
683    + SubAssign<F>
684    + Mul<F, Output = Self>
685    + MulAssign<F>
686{
687    /// Dot product between algebra elements and base field scalars.
688    ///
689    /// Given arrays `a` (algebra) and `f` (scalars), computes:
690    ///
691    /// ```text
692    ///   result = a[0]*f[0] + a[1]*f[1] + ... + a[N-1]*f[N-1]
693    /// ```
694    ///
695    /// Uses a tree-structured summation to minimize dependency chains and
696    /// maximize throughput on pipelined architectures.
697    #[must_use]
698    #[inline]
699    fn mixed_dot_product<const N: usize>(a: &[Self; N], f: &[F; N]) -> Self
700    where
701        F: Dup,
702    {
703        let products: [Self; N] = core::array::from_fn(|i| a[i].dup() * f[i].dup());
704        Self::sum_array::<N>(&products)
705    }
706
707    /// Optimal chunk size for [`batched_linear_combination`](Self::batched_linear_combination).
708    ///
709    /// Override in implementations where a different chunk size is faster.
710    /// Must be one of 1, 2, 4, 8, 16, 32, or 64; other values cause a compile error.
711    const BATCHED_LC_CHUNK: usize = 8;
712
713    /// Runtime-length linear combination: `Σ values[i] * coeffs[i]`.
714    ///
715    /// Like [`mixed_dot_product`](Self::mixed_dot_product) but for slices whose
716    /// length is not known at compile time. Processes in chunks of
717    /// [`BATCHED_LC_CHUNK`](Self::BATCHED_LC_CHUNK), delegating each chunk to
718    /// `mixed_dot_product` to leverage SIMD-specialized overrides.
719    #[must_use]
720    #[inline]
721    fn batched_linear_combination(values: &[Self], coeffs: &[F]) -> Self
722    where
723        F: Dup,
724    {
725        const {
726            assert!(
727                matches!(Self::BATCHED_LC_CHUNK, 1 | 2 | 4 | 8 | 16 | 32 | 64),
728                "BATCHED_LC_CHUNK must be one of 1, 2, 4, 8, 16, 32, or 64"
729            );
730        }
731        match Self::BATCHED_LC_CHUNK {
732            1 => chunked_linear_combination::<1, Self, F>(values, coeffs),
733            2 => chunked_linear_combination::<2, Self, F>(values, coeffs),
734            4 => chunked_linear_combination::<4, Self, F>(values, coeffs),
735            8 => chunked_linear_combination::<8, Self, F>(values, coeffs),
736            16 => chunked_linear_combination::<16, Self, F>(values, coeffs),
737            32 => chunked_linear_combination::<32, Self, F>(values, coeffs),
738            64 => chunked_linear_combination::<64, Self, F>(values, coeffs),
739            _ => unreachable!(),
740        }
741    }
742}
743
744/// Compute `Σ values[i] * coeffs[i]` over `N` pairs.
745///
746/// A single long sum forces every add to wait for the previous one. Instead,
747/// we split the pairs into groups of `CHUNK`, sum each group on its own, and
748/// add up the group totals. Several partial sums run in parallel on the CPU,
749/// so the total latency is shorter than one straight chain.
750///
751/// The result is the same for every valid `CHUNK` — only the speed changes.
752///
753/// # Layout
754///
755/// For `N = q * CHUNK + r` with `0 <= r < CHUNK`:
756///
757/// ```text
758///     ┌── group 0 ──┬── group 1 ──┬─ ... ─┬── tail (r) ──┐
759///     │   CHUNK     │   CHUNK     │       │   r pairs    │
760///     └──────┬──────┴──────┬──────┴───────┴──────┬───────┘
761///            ▼             ▼                     ▼
762///       tree-sum      tree-sum             scalar adds
763///            └──► acc ◄────┴──────► acc ◄────────┘
764/// ```
765///
766/// # Panics
767///
768/// Compile-time panic if `CHUNK` is zero.
769#[must_use]
770#[inline]
771pub fn chunked_mixed_dot_product<
772    const CHUNK: usize,
773    A: Algebra<F> + Dup,
774    F: Dup,
775    const N: usize,
776>(
777    values: &[A; N],
778    coeffs: &[F; N],
779) -> A {
780    // CHUNK = 0 would make the group count undefined.
781    const { assert!(CHUNK != 0, "chunked_mixed_dot_product requires CHUNK > 0") }
782
783    // Fast path: N fits in one group → single balanced tree, no outer loop.
784    if N <= CHUNK {
785        let products: [A; N] = core::array::from_fn(|i| values[i].dup() * coeffs[i].dup());
786        return A::sum_array::<N>(&products);
787    }
788
789    // Split off q complete groups; r leftover pairs go to the tail.
790    let (val_chunks, val_rem) = values.as_slice().as_chunks::<CHUNK>();
791    let (coeff_chunks, coeff_rem) = coeffs.as_slice().as_chunks::<CHUNK>();
792    debug_assert_eq!(val_chunks.len(), coeff_chunks.len());
793
794    // One add per group; runs in parallel with the next group's multiplies.
795    let mut acc = A::ZERO;
796    for (vc, cc) in zip(val_chunks, coeff_chunks) {
797        let products: [A; CHUNK] = core::array::from_fn(|i| vc[i].dup() * cc[i].dup());
798        // Balanced tree of depth log2(CHUNK), folded into acc.
799        acc += A::sum_array::<CHUNK>(&products);
800    }
801
802    // Tail: at most CHUNK - 1 pairs as a serial multiply-add chain.
803    debug_assert_eq!(val_rem.len(), coeff_rem.len());
804    for (v, c) in zip(val_rem, coeff_rem) {
805        acc += v.dup() * c.dup();
806    }
807    acc
808}
809
810/// Lower a runtime chunk size into a const-generic call to the fixed-chunk dot product.
811///
812/// Each backend picks its preferred chunk size at runtime; the inner routine
813/// needs it as a const for unrolling. This wrapper bridges the gap.
814///
815/// Supported sizes: `1, 2, 4, 8, 16, 32, 64` — powers of two only, so the
816/// inner balanced tree stays balanced.
817///
818/// # Panics
819///
820/// Runtime panic if `chunk` is outside the supported set.
821#[must_use]
822#[inline]
823pub fn dispatch_chunked_mixed_dot_product<A: Algebra<F> + Dup, F: Dup, const N: usize>(
824    values: &[A; N],
825    coeffs: &[F; N],
826    chunk: usize,
827) -> A {
828    match chunk {
829        1 => chunked_mixed_dot_product::<1, A, F, N>(values, coeffs),
830        2 => chunked_mixed_dot_product::<2, A, F, N>(values, coeffs),
831        4 => chunked_mixed_dot_product::<4, A, F, N>(values, coeffs),
832        8 => chunked_mixed_dot_product::<8, A, F, N>(values, coeffs),
833        16 => chunked_mixed_dot_product::<16, A, F, N>(values, coeffs),
834        32 => chunked_mixed_dot_product::<32, A, F, N>(values, coeffs),
835        64 => chunked_mixed_dot_product::<64, A, F, N>(values, coeffs),
836        // Unsupported chunk = configuration bug in a backend.
837        _ => panic!("mixed_dot_product chunk must be one of 1, 2, 4, 8, 16, 32, or 64"),
838    }
839}
840
841/// Linear combination over runtime-length slices, processing in chunks of `CHUNK`.
842///
843/// Computes `Σ values[i] * coeffs[i]` by batching into fixed-size chunks and
844/// delegating each to [`Algebra::mixed_dot_product`], which SIMD implementations
845/// override with fused multiply-accumulate intrinsics.
846///
847/// This is the implementation backing [`Algebra::batched_linear_combination`].
848/// Use it directly when overriding that method with a different chunk size.
849#[must_use]
850#[inline]
851pub fn chunked_linear_combination<const CHUNK: usize, A: Algebra<F> + Dup, F: Dup>(
852    values: &[A],
853    coeffs: &[F],
854) -> A {
855    const { assert!(CHUNK != 0, "chunked_linear_combination requires CHUNK > 0") }
856    assert_eq!(values.len(), coeffs.len());
857
858    let (val_chunks, val_rem) = values.as_chunks::<CHUNK>();
859    let (coeff_chunks, coeff_rem) = coeffs.as_chunks::<CHUNK>();
860
861    debug_assert_eq!(val_chunks.len(), coeff_chunks.len());
862    let mut acc = A::ZERO;
863    for (vc, cc) in zip(val_chunks, coeff_chunks) {
864        acc += A::mixed_dot_product::<CHUNK>(vc, cc);
865    }
866
867    debug_assert_eq!(val_rem.len(), coeff_rem.len());
868    for (v, c) in zip(val_rem, coeff_rem) {
869        acc += v.dup() * c.dup();
870    }
871    acc
872}
873
874// Every ring is an algebra over itself.
875impl<R: PrimeCharacteristicRing> Algebra<R> for R {}
876
877/// A collection of methods designed to help hash field elements.
878///
879/// Most fields will want to reimplement many/all of these methods as the default implementations
880/// are slow and involve converting to/from byte representations.
881pub trait RawDataSerializable: Sized {
882    /// The number of bytes which this field element occupies in memory.
883    /// Must be equal to the length of self.into_bytes().
884    const NUM_BYTES: usize;
885
886    /// Convert a field element into a collection of bytes.
887    #[must_use]
888    fn into_bytes(self) -> impl IntoIterator<Item = u8>;
889
890    /// Convert an iterator of field elements into an iterator of bytes.
891    #[must_use]
892    fn into_byte_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u8> {
893        input.into_iter().flat_map(|elem| elem.into_bytes())
894    }
895
896    /// Convert an iterator of field elements into an iterator of u32s.
897    ///
898    /// If `NUM_BYTES` does not divide `4`, multiple `F`s may be packed together to make a single `u32`. Furthermore,
899    /// if `NUM_BYTES * input.len()` does not divide `4`, the final `u32` will involve padding bytes which are set to `0`.
900    #[must_use]
901    fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
902        let bytes = Self::into_byte_stream(input);
903        iter_array_chunks_padded(bytes, 0).map(u32::from_le_bytes)
904    }
905
906    /// Convert an iterator of field elements into an iterator of u64s.
907    ///
908    /// If `NUM_BYTES` does not divide `8`, multiple `F`s may be packed together to make a single `u64`. Furthermore,
909    /// if `NUM_BYTES * input.len()` does not divide `8`, the final `u64` will involve padding bytes which are set to `0`.
910    #[must_use]
911    fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
912        let bytes = Self::into_byte_stream(input);
913        iter_array_chunks_padded(bytes, 0).map(u64::from_le_bytes)
914    }
915
916    /// Convert an iterator of field element arrays into an iterator of byte arrays.
917    ///
918    /// Converts an element `[F; N]` into the byte array `[[u8; N]; NUM_BYTES]`. This is
919    /// intended for use with vectorized hash functions which use vector operations
920    /// to compute several hashes in parallel.
921    #[must_use]
922    fn into_parallel_byte_streams<const N: usize>(
923        input: impl IntoIterator<Item = [Self; N]>,
924    ) -> impl IntoIterator<Item = [u8; N]> {
925        input.into_iter().flat_map(|vector| {
926            let bytes = vector.map(|elem| elem.into_bytes().into_iter().collect::<Vec<_>>());
927            (0..Self::NUM_BYTES).map(move |i| array::from_fn(|j| bytes[j][i]))
928        })
929    }
930
931    /// Convert an iterator of field element arrays into an iterator of u32 arrays.
932    ///
933    /// Converts an element `[F; N]` into the u32 array `[[u32; N]; NUM_BYTES/4]`. This is
934    /// intended for use with vectorized hash functions which use vector operations
935    /// to compute several hashes in parallel.
936    ///
937    /// This function is guaranteed to be equivalent to starting with `Iterator<[F; N]>` performing a transpose
938    /// operation to get `[Iterator<F>; N]`, calling `into_u32_stream` on each element to get `[Iterator<u32>; N]` and then
939    /// performing another transpose operation to get `Iterator<[u32; N]>`.
940    ///
941    /// If `NUM_BYTES` does not divide `4`, multiple `[F; N]`s may be packed together to make a single `[u32; N]`. Furthermore,
942    /// if `NUM_BYTES * input.len()` does not divide `4`, the final `[u32; N]` will involve padding bytes which are set to `0`.
943    #[must_use]
944    fn into_parallel_u32_streams<const N: usize>(
945        input: impl IntoIterator<Item = [Self; N]>,
946    ) -> impl IntoIterator<Item = [u32; N]> {
947        let bytes = Self::into_parallel_byte_streams(input);
948        iter_array_chunks_padded(bytes, [0; N]).map(|byte_array: [[u8; N]; 4]| {
949            array::from_fn(|i| u32::from_le_bytes(array::from_fn(|j| byte_array[j][i])))
950        })
951    }
952
953    /// Convert an iterator of field element arrays into an iterator of u64 arrays.
954    ///
955    /// Converts an element `[F; N]` into the u64 array `[[u64; N]; NUM_BYTES/8]`. This is
956    /// intended for use with vectorized hash functions which use vector operations
957    /// to compute several hashes in parallel.
958    ///
959    /// This function is guaranteed to be equivalent to starting with `Iterator<[F; N]>` performing a transpose
960    /// operation to get `[Iterator<F>; N]`, calling `into_u64_stream` on each element to get `[Iterator<u64>; N]` and then
961    /// performing another transpose operation to get `Iterator<[u64; N]>`.
962    ///
963    /// If `NUM_BYTES` does not divide `8`, multiple `[F; N]`s may be packed together to make a single `[u64; N]`. Furthermore,
964    /// if `NUM_BYTES * input.len()` does not divide `8`, the final `[u64; N]` will involve padding bytes which are set to `0`.
965    #[must_use]
966    fn into_parallel_u64_streams<const N: usize>(
967        input: impl IntoIterator<Item = [Self; N]>,
968    ) -> impl IntoIterator<Item = [u64; N]> {
969        let bytes = Self::into_parallel_byte_streams(input);
970        iter_array_chunks_padded(bytes, [0; N]).map(|byte_array: [[u8; N]; 8]| {
971            array::from_fn(|i| u64::from_le_bytes(array::from_fn(|j| byte_array[j][i])))
972        })
973    }
974}
975
976/// A field `F`. This permits both modular fields `ℤ/p` along with their field extensions.
977///
978/// A ring is a field if every element `x` has a unique multiplicative inverse `x^{-1}`
979/// which satisfies `x * x^{-1} = F::ONE`.
980pub trait Field:
981    Algebra<Self>
982    + RawDataSerializable
983    + Packable
984    + 'static
985    + Copy
986    + Div<Self, Output = Self>
987    + DivAssign
988    + Add<Self::Packing, Output = Self::Packing>
989    + Sub<Self::Packing, Output = Self::Packing>
990    + Mul<Self::Packing, Output = Self::Packing>
991    + Eq
992    + Hash
993    + Send
994    + Sync
995    + Display
996    + Serialize
997    + DeserializeOwned
998{
999    type Packing: PackedField<Scalar = Self>;
1000
1001    /// A generator of this field's multiplicative group.
1002    const GENERATOR: Self;
1003
1004    /// Whether evaluating multiple packed vectors of this field in lockstep (to overlap
1005    /// independent dependency chains and hide packed-multiplication latency) is expected
1006    /// to help throughput for this field.
1007    ///
1008    /// Only [`p3_uni_stark::quotient_values`](https://docs.rs/p3-uni-stark)'s `aarch64`
1009    /// (`neon`)-gated path reads this constant; on every other target it has no effect,
1010    /// so leaving it at the default is always safe there.
1011    ///
1012    /// Defaults to `false`, so fields fail safe into the plain (non-lockstep) path unless
1013    /// explicitly measured to benefit. Override to `true` only once benchmarks confirm the
1014    /// field's packed multiplication is latency-bound enough for lockstep evaluation to help.
1015    const BENEFITS_FROM_LOCKSTEP_EVALUATION: bool = false;
1016
1017    /// Check if the given field element is equal to the unique additive identity (ZERO).
1018    #[must_use]
1019    #[inline]
1020    fn is_zero(&self) -> bool {
1021        *self == Self::ZERO
1022    }
1023
1024    /// Check if the given field element is equal to the unique multiplicative identity (ONE).
1025    #[must_use]
1026    #[inline]
1027    fn is_one(&self) -> bool {
1028        *self == Self::ONE
1029    }
1030
1031    /// The multiplicative inverse of this field element, if it exists.
1032    ///
1033    /// NOTE: The inverse of `0` is undefined and will return `None`.
1034    #[must_use]
1035    fn try_inverse(&self) -> Option<Self>;
1036
1037    /// The multiplicative inverse of this field element.
1038    ///
1039    /// # Panics
1040    /// The function will panic if the field element is `0`.
1041    /// Use try_inverse if you want to handle this case.
1042    #[must_use]
1043    fn inverse(&self) -> Self {
1044        self.try_inverse().expect("Tried to invert zero")
1045    }
1046
1047    /// A square root of this field element, if one exists.
1048    ///
1049    /// Returns `Some(r)` with `r * r == *self` when this element is a quadratic
1050    /// residue, and `None` when it is a quadratic non-residue. `ZERO` returns
1051    /// `Some(ZERO)`. When two square roots exist, which one is returned is
1052    /// unspecified.
1053    ///
1054    /// The default implementation uses the Tonelli–Shanks algorithm. Fields with
1055    /// a more direct formula (e.g. those with `|F| ≡ 3 mod 4`) may override it.
1056    #[must_use]
1057    fn try_sqrt(&self) -> Option<Self> {
1058        crate::sqrt::tonelli_shanks(*self)
1059    }
1060
1061    /// The `i`-th element of a fixed injective enumeration of `Self`, used as an
1062    /// interpolation node. Must satisfy `interpolation_node(0) == ZERO` and
1063    /// `interpolation_node(1) == ONE`, and be injective for every `i` below the size
1064    /// of the field — no enumeration can do better, and a field smaller than the
1065    /// degree of the polynomial being interpolated is unusable for that protocol
1066    /// anyway. Round-polynomial degrees are tiny, so `0..min(64, |Self|)` is the
1067    /// tested range.
1068    ///
1069    /// The default maps `i` through the prime subfield and is injective only while
1070    /// `i` is below the characteristic. Fields of characteristic below `2^32` must
1071    /// override it.
1072    #[must_use]
1073    fn interpolation_node(i: usize) -> Self {
1074        Self::from_usize(i)
1075    }
1076
1077    /// Add two slices of field elements together, returning the result in the first slice.
1078    ///
1079    /// Makes use of packing to speed up the addition.
1080    ///
1081    /// This is optimal for cases where the two slices are small to medium length. E.g. between
1082    /// `F::Packing::WIDTH` and roughly however many elements fit in a cache line.
1083    ///
1084    /// For larger slices, it's likely worthwhile to use parallelization before calling this.
1085    /// Similarly if you need to add a large number of slices together, it's best to
1086    /// break them into small chunks and call this on the smaller chunks.
1087    ///
1088    /// # Panics
1089    /// The function will panic if the lengths of the two slices are not equal.
1090    #[inline]
1091    fn add_slices(slice_1: &mut [Self], slice_2: &[Self]) {
1092        let (shorts_1, suffix_1) = Self::Packing::pack_slice_with_suffix_mut(slice_1);
1093        let (shorts_2, suffix_2) = Self::Packing::pack_slice_with_suffix(slice_2);
1094        debug_assert_eq!(shorts_1.len(), shorts_2.len());
1095        debug_assert_eq!(suffix_1.len(), suffix_2.len());
1096        for (x_1, &x_2) in shorts_1.iter_mut().zip(shorts_2) {
1097            *x_1 += x_2;
1098        }
1099        for (x_1, &x_2) in suffix_1.iter_mut().zip(suffix_2) {
1100            *x_1 += x_2;
1101        }
1102    }
1103
1104    /// Accumulate `acc[c * N + j] += scales[j] * row[c]` over a stream of packed rows.
1105    ///
1106    /// Each item provides one matrix row as `acc.len() / N` packed base-field words,
1107    /// together with the row's `N` extension-field weights. `acc` is laid out with the
1108    /// `N` weights of each word group adjacent, and its length must be a multiple of `N`.
1109    ///
1110    /// This is the inner kernel of batched columnwise (weighted-sum-of-rows) dot
1111    /// products. Fields may override it to defer modular reductions across rows.
1112    fn batched_columnwise_dot_product<EF, R, I, const N: usize>(
1113        acc: &mut [EF::ExtensionPacking],
1114        items: I,
1115    ) where
1116        EF: ExtensionField<Self>,
1117        R: Iterator<Item = Self::Packing>,
1118        I: Iterator<Item = (R, [EF; N])>,
1119    {
1120        generic_batched_columnwise_dot_product::<Self, EF, R, I, N>(acc, items);
1121    }
1122
1123    /// The number of elements in the field.
1124    ///
1125    /// This will either be prime if the field is a PrimeField or a power of a
1126    /// prime if the field is an extension field.
1127    #[must_use]
1128    fn order() -> BigUint;
1129
1130    /// The number of bits required to define an element of this field.
1131    ///
1132    /// Usually due to storage and practical reasons the memory size of
1133    /// a field element will be a little larger than bits().
1134    #[must_use]
1135    #[inline]
1136    fn bits() -> usize {
1137        Self::order().bits() as usize
1138    }
1139}
1140
1141/// The generic accumulation behind [`Field::batched_columnwise_dot_product`]:
1142/// `acc[c * N + j] += scales[j] * row[c]` over a stream of packed rows.
1143///
1144/// Kept as a free function so that specialized `Field` implementations can fall back
1145/// to it for extension degrees their kernels do not cover.
1146pub fn generic_batched_columnwise_dot_product<F, EF, R, I, const N: usize>(
1147    acc: &mut [EF::ExtensionPacking],
1148    items: I,
1149) where
1150    F: Field,
1151    EF: ExtensionField<F>,
1152    R: Iterator<Item = F::Packing>,
1153    I: Iterator<Item = (R, [EF; N])>,
1154{
1155    for (row, scales) in items {
1156        let packed_scales = scales.map(EF::ExtensionPacking::from);
1157        for (acc_c, r) in acc.as_chunks_mut::<N>().0.iter_mut().zip(row) {
1158            for (a, &s) in acc_c.iter_mut().zip(&packed_scales) {
1159                *a += s * r;
1160            }
1161        }
1162    }
1163}
1164
1165/// A field isomorphic to `ℤ/p` for some prime `p`.
1166///
1167/// There is a natural map from `ℤ` to `ℤ/p` which sends an integer `r` to its conjugacy class `[r]`.
1168/// Canonically, each conjugacy class `[r]` can be represented by the unique integer `s` in `[0, p - 1)`
1169/// satisfying `s = r mod p`. This however is often not the most convenient computational representation
1170/// and so internal representations of field elements might differ from this and may change over time.
1171pub trait PrimeField:
1172    Field
1173    + Ord
1174    + QuotientMap<u8>
1175    + QuotientMap<u16>
1176    + QuotientMap<u32>
1177    + QuotientMap<u64>
1178    + QuotientMap<u128>
1179    + QuotientMap<usize>
1180    + QuotientMap<i8>
1181    + QuotientMap<i16>
1182    + QuotientMap<i32>
1183    + QuotientMap<i64>
1184    + QuotientMap<i128>
1185    + QuotientMap<isize>
1186{
1187    /// Return the representative of `value` in canonical form
1188    /// which lies in the range `0 <= x < self.order()`.
1189    #[must_use]
1190    fn as_canonical_biguint(&self) -> BigUint;
1191}
1192
1193/// A prime field `ℤ/p` with order, `p < 2^64`.
1194pub trait PrimeField64: PrimeField {
1195    const ORDER_U64: u64;
1196
1197    /// Return the representative of `value` in canonical form
1198    /// which lies in the range `0 <= x < ORDER_U64`.
1199    #[must_use]
1200    fn as_canonical_u64(&self) -> u64;
1201
1202    /// Convert a field element to a `u64` such that any two field elements
1203    /// are converted to the same `u64` if and only if they represent the same value.
1204    ///
1205    /// This will be the fastest way to convert a field element to a `u64` and
1206    /// is intended for use in hashing. It will also be consistent across different targets.
1207    #[must_use]
1208    #[inline(always)]
1209    fn to_unique_u64(&self) -> u64 {
1210        // A simple default which is optimal for some fields.
1211        self.as_canonical_u64()
1212    }
1213}
1214
1215/// A prime field `ℤ/p` with order `p < 2^32`.
1216pub trait PrimeField32: PrimeField64 {
1217    const ORDER_U32: u32;
1218
1219    /// Return the representative of `value` in canonical form
1220    /// which lies in the range `0 <= x < ORDER_U64`.
1221    #[must_use]
1222    fn as_canonical_u32(&self) -> u32;
1223
1224    /// Convert a field element to a `u32` such that any two field elements
1225    /// are converted to the same `u32` if and only if they represent the same value.
1226    ///
1227    /// This will be the fastest way to convert a field element to a `u32` and
1228    /// is intended for use in hashing. It will also be consistent across different targets.
1229    #[must_use]
1230    #[inline(always)]
1231    fn to_unique_u32(&self) -> u32 {
1232        // A simple default which is optimal for some fields.
1233        self.as_canonical_u32()
1234    }
1235}
1236
1237/// A field `EF` which is also an algebra over a field `F`.
1238///
1239/// This provides a couple of convenience methods on top of the
1240/// standard methods provided by `Field`, `Algebra<F>` and `BasedVectorSpace<F>`.
1241///
1242/// It also provides a type which handles packed vectors of extension field elements.
1243pub trait ExtensionField<Base: Field>: Field + Algebra<Base> + BasedVectorSpace<Base> {
1244    type ExtensionPacking: PackedFieldExtension<Base, Self> + 'static + Copy + Send + Sync;
1245
1246    /// Determine if the given element lies in the base field.
1247    #[must_use]
1248    fn is_in_basefield(&self) -> bool;
1249
1250    /// If the element lies in the base field project it down.
1251    /// Otherwise return None.
1252    #[must_use]
1253    fn as_base(&self) -> Option<Base>;
1254
1255    /// Reassemble an element of `Self` from `D = DIMENSION` coefficients in `Self`
1256    /// via `Σⱼ basisⱼ · coeffsⱼ`. Returns `None` if `coeffs.len() != Self::DIMENSION`.
1257    ///
1258    /// This is the `Self`-coefficient counterpart to
1259    /// [`BasedVectorSpace::from_basis_coefficients_slice`], which takes coefficients
1260    /// in `Base`. It is the natural "lifting" operation in commit-and-open protocols:
1261    /// if an extension polynomial decomposes as `f(X) = Σⱼ basisⱼ · fⱼ(X)` with
1262    /// `fⱼ` over `Base`, then `f(z) = Σⱼ basisⱼ · fⱼ(z)` for any `z ∈ Self`.
1263    #[inline]
1264    #[must_use]
1265    fn from_ext_basis_coefficients(coeffs: &[Self]) -> Option<Self> {
1266        (coeffs.len() == Self::DIMENSION).then(|| {
1267            (0..Self::DIMENSION)
1268                .map(|j| Self::ith_basis_element(j).unwrap() * coeffs[j])
1269                .sum()
1270        })
1271    }
1272}
1273
1274// Every field is trivially a one dimensional extension over itself.
1275impl<F: Field> ExtensionField<F> for F {
1276    type ExtensionPacking = F::Packing;
1277
1278    #[inline]
1279    fn is_in_basefield(&self) -> bool {
1280        true
1281    }
1282
1283    #[inline]
1284    fn as_base(&self) -> Option<F> {
1285        Some(*self)
1286    }
1287
1288    #[inline]
1289    fn from_ext_basis_coefficients(coeffs: &[Self]) -> Option<Self> {
1290        (coeffs.len() == 1).then(|| coeffs[0])
1291    }
1292}
1293
1294/// A field which supplies information like the two-adicity of its multiplicative group, and methods
1295/// for obtaining two-adic generators.
1296pub trait TwoAdicField: Field {
1297    /// The number of factors of two in this field's multiplicative group.
1298    const TWO_ADICITY: usize;
1299
1300    /// Returns a generator of the multiplicative group of order `2^bits`.
1301    /// Assumes `bits <= TWO_ADICITY`, otherwise the result is undefined.
1302    #[must_use]
1303    fn two_adic_generator(bits: usize) -> Self;
1304}
1305
1306/// An iterator which returns the powers of a base element `b` shifted by current `c`: `c, c * b, c * b^2, ...`.
1307#[derive(Clone, Debug)]
1308pub struct Powers<R: PrimeCharacteristicRing> {
1309    pub base: R,
1310    pub current: R,
1311}
1312
1313impl<R: PrimeCharacteristicRing> Iterator for Powers<R> {
1314    type Item = R;
1315
1316    fn next(&mut self) -> Option<R> {
1317        let result = self.current.dup();
1318        self.current *= self.base.dup();
1319        Some(result)
1320    }
1321}
1322
1323impl<R: PrimeCharacteristicRing> Powers<R> {
1324    /// Returns an iterator yielding the first `n` powers.
1325    #[inline]
1326    #[must_use]
1327    pub const fn take(self, n: usize) -> BoundedPowers<R> {
1328        BoundedPowers { iter: self, n }
1329    }
1330
1331    /// Fills `slice` with the next `slice.len()` powers yielded by the iterator.
1332    #[inline]
1333    pub fn fill(self, slice: &mut [R]) {
1334        slice
1335            .iter_mut()
1336            .zip(self)
1337            .for_each(|(out, next)| *out = next);
1338    }
1339}
1340
1341impl<F: Field> Powers<F> {
1342    /// Wrapper for `self.take(n).collect()`.
1343    ///
1344    /// Bounded to `F: Field` on purpose: the body resolves `.collect()` to the inherent
1345    /// [`BoundedPowers::collect`] SIMD fast path, which only exists under `F: Field`.
1346    /// Defining this method under a wider bound (e.g. `PrimeCharacteristicRing`) would
1347    /// silently fall back to `Iterator::collect` and bypass packed-field acceleration.
1348    #[inline]
1349    #[must_use]
1350    pub fn collect_n(self, n: usize) -> Vec<F> {
1351        self.take(n).collect()
1352    }
1353}
1354
1355impl<F: Field> BoundedPowers<F> {
1356    /// Collect exactly `num_powers` ascending powers of `self.base`, starting at `self.current`.
1357    ///
1358    /// # Details
1359    ///
1360    /// The computation is split evenly amongst available threads, and each chunk is computed
1361    /// using packed fields. Small requests are computed on the current thread, as a parallel
1362    /// dispatch would cost more than the fill itself.
1363    ///
1364    /// # Performance
1365    ///
1366    /// Enable the `parallel` feature to enable parallelization.
1367    #[must_use]
1368    pub fn collect(self) -> Vec<F> {
1369        // Below this many scalars, a parallel dispatch costs more than the packed fill itself.
1370        const PARALLEL_THRESHOLD: usize = 1 << 10;
1371
1372        let num_powers = self.n;
1373
1374        // When num_powers is small, fallback to serial computation
1375        if num_powers < 16 {
1376            return self.take(num_powers).collect();
1377        }
1378
1379        // Allocate buffer storing packed powers, containing at least `num_powers` scalars.
1380        let width = F::Packing::WIDTH;
1381        let num_packed = num_powers.div_ceil(width);
1382        let mut points_packed = F::Packing::zero_vec(num_packed);
1383
1384        let base = self.iter.base;
1385        let shift = self.iter.current;
1386
1387        if num_powers < PARALLEL_THRESHOLD {
1388            F::Packing::packed_shifted_powers(base, shift).fill(&mut points_packed);
1389        } else {
1390            // Split computation evenly among threads
1391            let num_threads = current_num_threads().max(1);
1392            let chunk_size = num_packed.div_ceil(num_threads);
1393
1394            // Precompute base for each chunk.
1395            let chunk_base = base.exp_u64((chunk_size * width) as u64);
1396
1397            points_packed
1398                .par_chunks_mut(chunk_size)
1399                .enumerate()
1400                .for_each(|(chunk_idx, chunk_slice)| {
1401                    // First power in this chunk
1402                    let chunk_start = shift * chunk_base.exp_u64(chunk_idx as u64);
1403
1404                    // Fill the chunk with packed powers.
1405                    F::Packing::packed_shifted_powers(base, chunk_start).fill(chunk_slice);
1406                });
1407        }
1408
1409        // return the number of requested points, discarding the unused packed powers
1410        // SAFETY: size_of::<F::Packing> always divides size_of::<F::Packing>.
1411        let mut points = unsafe { flatten_to_base(points_packed) };
1412        points.truncate(num_powers);
1413        points
1414    }
1415}
1416
1417/// Same as [`Powers`], but returns a bounded number of powers.
1418#[derive(Clone, Debug)]
1419pub struct BoundedPowers<R: PrimeCharacteristicRing> {
1420    iter: Powers<R>,
1421    n: usize,
1422}
1423
1424impl<R: PrimeCharacteristicRing> Iterator for BoundedPowers<R> {
1425    type Item = R;
1426
1427    fn next(&mut self) -> Option<R> {
1428        (self.n != 0).then(|| {
1429            self.n -= 1;
1430            self.iter.next().unwrap()
1431        })
1432    }
1433
1434    #[inline]
1435    fn size_hint(&self) -> (usize, Option<usize>) {
1436        (self.n, Some(self.n))
1437    }
1438}
1439
1440impl<R: PrimeCharacteristicRing> ExactSizeIterator for BoundedPowers<R> {
1441    #[inline]
1442    fn len(&self) -> usize {
1443        self.n
1444    }
1445}