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};
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::{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 + Clone
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.clone() + self.clone()
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.clone() * 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.clone() * self.clone()
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.clone()
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.clone() + y.clone() - self.clone() * y.clone().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.clone()) * y.clone()
198 }
199
200 /// The vanishing polynomial for boolean values: `x * (1 - x)`.
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 // We use `x * (1 - x)` instead of `x * (x - 1)` as this lets us delegate to the `andn` function.
208 self.andn(self)
209 }
210
211 /// Exponentiation by a `u64` power.
212 ///
213 /// This uses the standard square and multiply approach.
214 /// For specific powers regularly used and known in advance,
215 /// this will be slower than custom addition chain exponentiation.
216 #[must_use]
217 #[inline]
218 fn exp_u64(&self, power: u64) -> Self {
219 let mut current = self.clone();
220 let mut product = Self::ONE;
221
222 for j in 0..bits_u64(power) {
223 if (power >> j) & 1 != 0 {
224 product *= current.clone();
225 }
226 current = current.square();
227 }
228 product
229 }
230
231 /// Exponentiation by a small constant power.
232 ///
233 /// For a collection of small values we implement custom multiplication chain circuits which can be faster than the
234 /// simpler square and multiply approach.
235 ///
236 /// For large values this defaults back to `self.exp_u64`.
237 #[must_use]
238 #[inline(always)]
239 fn exp_const_u64<const POWER: u64>(&self) -> Self {
240 match POWER {
241 0 => Self::ONE,
242 1 => self.clone(),
243 2 => self.square(),
244 3 => self.cube(),
245 4 => self.square().square(),
246 5 => self.square().square() * self.clone(),
247 6 => self.square().cube(),
248 7 => {
249 let x2 = self.square();
250 let x3 = x2.clone() * self.clone();
251 let x4 = x2.square();
252 x3 * x4
253 }
254 _ => self.exp_u64(POWER),
255 }
256 }
257
258 /// The elementary function `exp_power_of_2(a, power_log) = a^{2^power_log}`.
259 ///
260 /// Computed via repeated squaring.
261 #[must_use]
262 #[inline]
263 fn exp_power_of_2(&self, power_log: usize) -> Self {
264 let mut res = self.clone();
265 for _ in 0..power_log {
266 res = res.square();
267 }
268 res
269 }
270
271 /// The elementary function `mul_2exp_u64(a, exp) = a * 2^{exp}`.
272 ///
273 /// Here `2^{exp}` is computed using the square and multiply approach.
274 #[must_use]
275 #[inline]
276 fn mul_2exp_u64(&self, exp: u64) -> Self {
277 // Some rings might want to reimplement this to avoid the
278 // exponentiations (and potentially even the multiplication).
279 self.clone() * Self::TWO.exp_u64(exp)
280 }
281
282 /// Divide by a given power of two. `div_2exp_u64(a, exp) = a/2^exp`
283 ///
284 /// # Panics
285 /// The function will panic if the field has characteristic 2.
286 #[must_use]
287 #[inline]
288 fn div_2exp_u64(&self, exp: u64) -> Self {
289 // Some rings might want to reimplement this to avoid the
290 // exponentiations (and potentially even the multiplication).
291 self.clone() * Self::from_prime_subfield(Self::PrimeSubfield::ONE.halve().exp_u64(exp))
292 }
293
294 /// Construct an iterator which returns powers of `self`: `self^0, self^1, self^2, ...`.
295 #[must_use]
296 #[inline]
297 fn powers(&self) -> Powers<Self> {
298 self.shifted_powers(Self::ONE)
299 }
300
301 /// Construct an iterator which returns powers of `self` shifted by `start`: `start, start*self^1, start*self^2, ...`.
302 #[must_use]
303 #[inline]
304 fn shifted_powers(&self, start: Self) -> Powers<Self> {
305 Powers {
306 base: self.clone(),
307 current: start,
308 }
309 }
310
311 /// Compute the dot product of two vectors.
312 #[must_use]
313 #[inline]
314 fn dot_product<const N: usize>(u: &[Self; N], v: &[Self; N]) -> Self {
315 u.iter().zip(v).map(|(x, y)| x.clone() * y.clone()).sum()
316 }
317
318 /// Compute the sum of a slice of elements whose length is a compile time constant.
319 ///
320 /// The rust compiler doesn't realize that add is associative
321 /// so we help it out and minimize the dependency chains by hand.
322 /// Thus while this function has the same throughput as `input.iter().sum()`,
323 /// it will usually have much lower latency.
324 ///
325 /// # Panics
326 ///
327 /// May panic if the length of the input slice is not equal to `N`.
328 #[must_use]
329 #[inline]
330 fn sum_array<const N: usize>(input: &[Self]) -> Self {
331 // It looks a little strange but using a const parameter and an assert_eq! instead of
332 // using input.len() leads to a significant performance improvement.
333 // We could make this input &[Self; N] but that would require sticking .try_into().unwrap() everywhere.
334 // Checking godbolt, the compiler seems to unroll everything anyway.
335 assert_eq!(N, input.len());
336
337 // For `N <= 8` we implement a tree sum structure and for `N > 8` we break the input into
338 // chunks of `8`, perform a tree sum on each chunk and sum the results. The parameter `8`
339 // was determined experimentally by testing the speed of the poseidon2 internal layer computations.
340 // This is a useful benchmark as we have a mix of summations of size 15, 23 with other work in between.
341 // I only tested this on `AVX2` though so there might be a better value for other architectures.
342 match N {
343 0 => Self::ZERO,
344 1 => input[0].clone(),
345 2 => input[0].clone() + input[1].clone(),
346 3 => input[0].clone() + input[1].clone() + input[2].clone(),
347 4 => (input[0].clone() + input[1].clone()) + (input[2].clone() + input[3].clone()),
348 5 => Self::sum_array::<4>(&input[..4]) + Self::sum_array::<1>(&input[4..]),
349 6 => Self::sum_array::<4>(&input[..4]) + Self::sum_array::<2>(&input[4..]),
350 7 => Self::sum_array::<4>(&input[..4]) + Self::sum_array::<3>(&input[4..]),
351 8 => Self::sum_array::<4>(&input[..4]) + Self::sum_array::<4>(&input[4..]),
352 _ => {
353 // We know that N > 8 here so this saves an add over the usual
354 // initialisation of acc to Self::ZERO.
355 let mut acc = Self::sum_array::<8>(&input[..8]);
356 for i in (16..=N).step_by(8) {
357 acc += Self::sum_array::<8>(&input[(i - 8)..i]);
358 }
359 // This would be much cleaner if we could use const generic expressions but
360 // this will do for now.
361 match N & 7 {
362 0 => acc,
363 1 => acc + Self::sum_array::<1>(&input[(8 * (N / 8))..]),
364 2 => acc + Self::sum_array::<2>(&input[(8 * (N / 8))..]),
365 3 => acc + Self::sum_array::<3>(&input[(8 * (N / 8))..]),
366 4 => acc + Self::sum_array::<4>(&input[(8 * (N / 8))..]),
367 5 => acc + Self::sum_array::<5>(&input[(8 * (N / 8))..]),
368 6 => acc + Self::sum_array::<6>(&input[(8 * (N / 8))..]),
369 7 => acc + Self::sum_array::<7>(&input[(8 * (N / 8))..]),
370 _ => unreachable!(),
371 }
372 }
373 }
374 }
375
376 /// Allocates a vector of zero elements of length `len`. Many operating systems zero pages
377 /// before assigning them to a userspace process. In that case, our process should not need to
378 /// write zeros, which would be redundant. However, the compiler may not always recognize this.
379 ///
380 /// In particular, `vec![Self::ZERO; len]` appears to result in redundant userspace zeroing.
381 /// This is the default implementation, but implementers may wish to provide their own
382 /// implementation which transmutes something like `vec![0u32; len]`.
383 #[must_use]
384 #[inline]
385 fn zero_vec(len: usize) -> Vec<Self> {
386 vec![Self::ZERO; len]
387 }
388}
389
390/// A vector space `V` over `F` with a fixed basis. Fixing the basis allows elements of `V` to be
391/// converted to and from `DIMENSION` many elements of `F` which are interpreted as basis coefficients.
392///
393/// We usually expect `F` to be a field but do not enforce this and so allow it to be just a ring.
394/// This lets every ring implement `BasedVectorSpace<Self>` and is useful in a couple of other cases.
395///
396/// ## Safety
397/// We make no guarantees about consistency of the choice of basis across different versions of Plonky3.
398/// If this choice of basis changes, the behaviour of `BasedVectorSpace` will also change. Due to this,
399/// we recommend avoiding using this trait unless absolutely necessary.
400///
401/// ### Mathematical Description
402/// Given a vector space, `A` over `F`, a basis is a set of elements `B = {b_0, ..., b_{n-1}}`
403/// in `A` such that, given any element `a`, we can find a unique set of `n` elements of `F`,
404/// `f_0, ..., f_{n - 1}` satisfying `a = f_0 b_0 + ... + f_{n - 1} b_{n - 1}`. Thus the choice
405/// of `B` gives rise to a natural linear map between the vector space `A` and the canonical
406/// `n` dimensional vector space `F^n`.
407///
408/// This allows us to map between elements of `A` and arrays of `n` elements of `F`.
409/// Clearly this map depends entirely on the choice of basis `B` which may change
410/// across versions of Plonky3.
411///
412/// The situation is slightly more complicated in cases where `F` is not a field but boils down
413/// to an identical description once we enforce that `A` is a free module over `F`.
414pub trait BasedVectorSpace<F: PrimeCharacteristicRing>: Sized {
415 /// The dimension of the vector space, i.e. the number of elements in
416 /// its basis.
417 const DIMENSION: usize;
418
419 /// Fixes a basis for the algebra `A` and uses this to
420 /// map an element of `A` to a slice of `DIMENSION` `F` elements.
421 ///
422 /// # Safety
423 ///
424 /// The value produced by this function fundamentally depends
425 /// on the choice of basis. Care must be taken
426 /// to ensure portability if these values might ever be passed to
427 /// (or rederived within) another compilation environment where a
428 /// different basis might have been used.
429 #[must_use]
430 fn as_basis_coefficients_slice(&self) -> &[F];
431
432 /// Fixes a basis for the algebra `A` and uses this to
433 /// map `DIMENSION` `F` elements to an element of `A`.
434 ///
435 /// # Safety
436 ///
437 /// The value produced by this function fundamentally depends
438 /// on the choice of basis. Care must be taken
439 /// to ensure portability if these values might ever be passed to
440 /// (or rederived within) another compilation environment where a
441 /// different basis might have been used.
442 ///
443 /// Returns `None` if the length of the slice is different to `DIMENSION`.
444 #[must_use]
445 #[inline]
446 fn from_basis_coefficients_slice(slice: &[F]) -> Option<Self> {
447 Self::from_basis_coefficients_iter(slice.iter().cloned())
448 }
449
450 /// Fixes a basis for the algebra `A` and uses this to
451 /// map `DIMENSION` `F` elements to an element of `A`. Similar
452 /// to `core:array::from_fn`, the `DIMENSION` `F` elements are
453 /// given by `Fn(0), ..., Fn(DIMENSION - 1)` called in that order.
454 ///
455 /// # Safety
456 ///
457 /// The value produced by this function fundamentally depends
458 /// on the choice of basis. Care must be taken
459 /// to ensure portability if these values might ever be passed to
460 /// (or rederived within) another compilation environment where a
461 /// different basis might have been used.
462 #[must_use]
463 fn from_basis_coefficients_fn<Fn: FnMut(usize) -> F>(f: Fn) -> Self;
464
465 /// Fixes a basis for the algebra `A` and uses this to
466 /// map `DIMENSION` `F` elements to an element of `A`.
467 ///
468 /// # Safety
469 ///
470 /// The value produced by this function fundamentally depends
471 /// on the choice of basis. Care must be taken
472 /// to ensure portability if these values might ever be passed to
473 /// (or rederived within) another compilation environment where a
474 /// different basis might have been used.
475 ///
476 /// Returns `None` if the length of the iterator is different to `DIMENSION`.
477 #[must_use]
478 fn from_basis_coefficients_iter<I: ExactSizeIterator<Item = F>>(iter: I) -> Option<Self>;
479
480 /// Given a basis for the Algebra `A`, return the i'th basis element.
481 ///
482 /// # Safety
483 ///
484 /// The value produced by this function fundamentally depends
485 /// on the choice of basis. Care must be taken
486 /// to ensure portability if these values might ever be passed to
487 /// (or rederived within) another compilation environment where a
488 /// different basis might have been used.
489 ///
490 /// Returns `None` if `i` is greater than or equal to `DIMENSION`.
491 #[must_use]
492 #[inline]
493 fn ith_basis_element(i: usize) -> Option<Self> {
494 (i < Self::DIMENSION).then(|| Self::from_basis_coefficients_fn(|j| F::from_bool(i == j)))
495 }
496
497 /// Convert from a vector of `Self` to a vector of `F` by flattening the basis coefficients.
498 ///
499 /// Depending on the `BasedVectorSpace` this may be essentially a no-op and should certainly
500 /// be reimplemented in those cases.
501 ///
502 /// # Safety
503 ///
504 /// The value produced by this function fundamentally depends
505 /// on the choice of basis. Care must be taken
506 /// to ensure portability if these values might ever be passed to
507 /// (or rederived within) another compilation environment where a
508 /// different basis might have been used.
509 #[must_use]
510 #[inline]
511 fn flatten_to_base(vec: Vec<Self>) -> Vec<F> {
512 vec.into_iter()
513 .flat_map(|x| x.as_basis_coefficients_slice().to_vec())
514 .collect()
515 }
516
517 /// Convert from a vector of `F` to a vector of `Self` by combining the basis coefficients.
518 ///
519 /// Depending on the `BasedVectorSpace` this may be essentially a no-op and should certainly
520 /// be reimplemented in those cases.
521 ///
522 /// # Panics
523 /// This will panic if the length of `vec` is not a multiple of `Self::DIMENSION`.
524 ///
525 /// # Safety
526 ///
527 /// The value produced by this function fundamentally depends
528 /// on the choice of basis. Care must be taken
529 /// to ensure portability if these values might ever be passed to
530 /// (or rederived within) another compilation environment where a
531 /// different basis might have been used.
532 #[must_use]
533 #[inline]
534 fn reconstitute_from_base(vec: Vec<F>) -> Vec<Self>
535 where
536 F: Sync,
537 Self: Send,
538 {
539 assert_eq!(vec.len() % Self::DIMENSION, 0);
540
541 vec.par_chunks_exact(Self::DIMENSION)
542 .map(|chunk| {
543 Self::from_basis_coefficients_slice(chunk)
544 .expect("Chunk length not equal to dimension")
545 })
546 .collect()
547 }
548}
549
550impl<F: PrimeCharacteristicRing> BasedVectorSpace<F> for F {
551 const DIMENSION: usize = 1;
552
553 #[inline]
554 fn as_basis_coefficients_slice(&self) -> &[F] {
555 slice::from_ref(self)
556 }
557
558 #[inline]
559 fn from_basis_coefficients_fn<Fn: FnMut(usize) -> F>(mut f: Fn) -> Self {
560 f(0)
561 }
562
563 #[inline]
564 fn from_basis_coefficients_iter<I: ExactSizeIterator<Item = F>>(mut iter: I) -> Option<Self> {
565 (iter.len() == 1).then(|| iter.next().unwrap()) // Unwrap will not panic as we know the length is 1.
566 }
567
568 #[inline]
569 fn flatten_to_base(vec: Vec<Self>) -> Vec<F> {
570 vec
571 }
572
573 #[inline]
574 fn reconstitute_from_base(vec: Vec<F>) -> Vec<Self> {
575 vec
576 }
577}
578
579/// A ring implements `InjectiveMonomial<N>` if the algebraic function
580/// `f(x) = x^N` is an injective map on elements of the ring.
581///
582/// We do not enforce that this map be invertible as there are useful
583/// cases such as polynomials or symbolic expressions where no inverse exists.
584///
585/// However, if the ring is a field with order `q` or an array of such field elements,
586/// then `f(x) = x^N` will be injective if and only if it is invertible and so in
587/// such cases this monomial acts as a permutation. Moreover, this will occur
588/// exactly when `N` and `q - 1` are relatively prime i.e. `gcd(N, q - 1) = 1`.
589pub trait InjectiveMonomial<const N: u64>: PrimeCharacteristicRing {
590 /// Compute `x -> x^n` for a given `n > 1` such that this
591 /// map is injective.
592 #[must_use]
593 #[inline]
594 fn injective_exp_n(&self) -> Self {
595 self.exp_const_u64::<N>()
596 }
597}
598
599/// A ring implements `PermutationMonomial<N>` if the algebraic function
600/// `f(x) = x^N` is invertible and thus acts as a permutation on elements of the ring.
601///
602/// In all cases we care about, this means that we can find another integer `K` such
603/// that `x = x^{NK}` for all elements of our ring.
604pub trait PermutationMonomial<const N: u64>: InjectiveMonomial<N> {
605 /// Compute `x -> x^K` for a given `K > 1` such that
606 /// `x^{NK} = x` for all elements `x`.
607 #[must_use]
608 fn injective_exp_root_n(&self) -> Self;
609}
610
611/// A ring `R` implements `Algebra<F>` if there is an injective homomorphism
612/// from `F` into `R`; in particular only `F::ZERO` maps to `R::ZERO`.
613///
614/// For the most part, we will usually expect `F` to be a field but there
615/// are a few cases where it is handy to allow it to just be a ring. In
616/// particular, every ring naturally implements `Algebra<Self>`.
617///
618/// ### Mathematical Description
619///
620/// Let `x` and `y` denote arbitrary elements of `F`. Then
621/// we require that our map `from` has the properties:
622/// - Preserves Identity: `from(F::ONE) = R::ONE`
623/// - Commutes with Addition: `from(x + y) = from(x) + from(y)`
624/// - Commutes with Multiplication: `from(x * y) = from(x) * from(y)`
625///
626/// Such maps are known as ring homomorphisms and are injective if the
627/// only element which maps to `R::ZERO` is `F::ZERO`.
628///
629/// The existence of this map makes `R` into an `F`-module and hence an `F`-algebra.
630/// If, additionally, `R` is a field, then this makes `R` a field extension of `F`.
631pub trait Algebra<F>:
632 PrimeCharacteristicRing
633 + From<F>
634 + Add<F, Output = Self>
635 + AddAssign<F>
636 + Sub<F, Output = Self>
637 + SubAssign<F>
638 + Mul<F, Output = Self>
639 + MulAssign<F>
640{
641}
642
643// Every ring is an algebra over itself.
644impl<R: PrimeCharacteristicRing> Algebra<R> for R {}
645
646/// A collection of methods designed to help hash field elements.
647///
648/// Most fields will want to reimplement many/all of these methods as the default implementations
649/// are slow and involve converting to/from byte representations.
650pub trait RawDataSerializable: Sized {
651 /// The number of bytes which this field element occupies in memory.
652 /// Must be equal to the length of self.into_bytes().
653 const NUM_BYTES: usize;
654
655 /// Convert a field element into a collection of bytes.
656 #[must_use]
657 fn into_bytes(self) -> impl IntoIterator<Item = u8>;
658
659 /// Convert an iterator of field elements into an iterator of bytes.
660 #[must_use]
661 fn into_byte_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u8> {
662 input.into_iter().flat_map(|elem| elem.into_bytes())
663 }
664
665 /// Convert an iterator of field elements into an iterator of u32s.
666 ///
667 /// If `NUM_BYTES` does not divide `4`, multiple `F`s may be packed together to make a single `u32`. Furthermore,
668 /// if `NUM_BYTES * input.len()` does not divide `4`, the final `u32` will involve padding bytes which are set to `0`.
669 #[must_use]
670 fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
671 let bytes = Self::into_byte_stream(input);
672 iter_array_chunks_padded(bytes, 0).map(u32::from_le_bytes)
673 }
674
675 /// Convert an iterator of field elements into an iterator of u64s.
676 ///
677 /// If `NUM_BYTES` does not divide `8`, multiple `F`s may be packed together to make a single `u64`. Furthermore,
678 /// if `NUM_BYTES * input.len()` does not divide `8`, the final `u64` will involve padding bytes which are set to `0`.
679 #[must_use]
680 fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
681 let bytes = Self::into_byte_stream(input);
682 iter_array_chunks_padded(bytes, 0).map(u64::from_le_bytes)
683 }
684
685 /// Convert an iterator of field element arrays into an iterator of byte arrays.
686 ///
687 /// Converts an element `[F; N]` into the byte array `[[u8; N]; NUM_BYTES]`. This is
688 /// intended for use with vectorized hash functions which use vector operations
689 /// to compute several hashes in parallel.
690 #[must_use]
691 fn into_parallel_byte_streams<const N: usize>(
692 input: impl IntoIterator<Item = [Self; N]>,
693 ) -> impl IntoIterator<Item = [u8; N]> {
694 input.into_iter().flat_map(|vector| {
695 let bytes = vector.map(|elem| elem.into_bytes().into_iter().collect::<Vec<_>>());
696 (0..Self::NUM_BYTES).map(move |i| array::from_fn(|j| bytes[j][i]))
697 })
698 }
699
700 /// Convert an iterator of field element arrays into an iterator of u32 arrays.
701 ///
702 /// Converts an element `[F; N]` into the u32 array `[[u32; N]; NUM_BYTES/4]`. This is
703 /// intended for use with vectorized hash functions which use vector operations
704 /// to compute several hashes in parallel.
705 ///
706 /// This function is guaranteed to be equivalent to starting with `Iterator<[F; N]>` performing a transpose
707 /// operation to get `[Iterator<F>; N]`, calling `into_u32_stream` on each element to get `[Iterator<u32>; N]` and then
708 /// performing another transpose operation to get `Iterator<[u32; N]>`.
709 ///
710 /// If `NUM_BYTES` does not divide `4`, multiple `[F; N]`s may be packed together to make a single `[u32; N]`. Furthermore,
711 /// if `NUM_BYTES * input.len()` does not divide `4`, the final `[u32; N]` will involve padding bytes which are set to `0`.
712 #[must_use]
713 fn into_parallel_u32_streams<const N: usize>(
714 input: impl IntoIterator<Item = [Self; N]>,
715 ) -> impl IntoIterator<Item = [u32; N]> {
716 let bytes = Self::into_parallel_byte_streams(input);
717 iter_array_chunks_padded(bytes, [0; N]).map(|byte_array: [[u8; N]; 4]| {
718 array::from_fn(|i| u32::from_le_bytes(array::from_fn(|j| byte_array[j][i])))
719 })
720 }
721
722 /// Convert an iterator of field element arrays into an iterator of u64 arrays.
723 ///
724 /// Converts an element `[F; N]` into the u64 array `[[u64; N]; NUM_BYTES/8]`. This is
725 /// intended for use with vectorized hash functions which use vector operations
726 /// to compute several hashes in parallel.
727 ///
728 /// This function is guaranteed to be equivalent to starting with `Iterator<[F; N]>` performing a transpose
729 /// operation to get `[Iterator<F>; N]`, calling `into_u64_stream` on each element to get `[Iterator<u64>; N]` and then
730 /// performing another transpose operation to get `Iterator<[u64; N]>`.
731 ///
732 /// If `NUM_BYTES` does not divide `8`, multiple `[F; N]`s may be packed together to make a single `[u64; N]`. Furthermore,
733 /// if `NUM_BYTES * input.len()` does not divide `8`, the final `[u64; N]` will involve padding bytes which are set to `0`.
734 #[must_use]
735 fn into_parallel_u64_streams<const N: usize>(
736 input: impl IntoIterator<Item = [Self; N]>,
737 ) -> impl IntoIterator<Item = [u64; N]> {
738 let bytes = Self::into_parallel_byte_streams(input);
739 iter_array_chunks_padded(bytes, [0; N]).map(|byte_array: [[u8; N]; 8]| {
740 array::from_fn(|i| u64::from_le_bytes(array::from_fn(|j| byte_array[j][i])))
741 })
742 }
743}
744
745/// A field `F`. This permits both modular fields `ℤ/p` along with their field extensions.
746///
747/// A ring is a field if every element `x` has a unique multiplicative inverse `x^{-1}`
748/// which satisfies `x * x^{-1} = F::ONE`.
749pub trait Field:
750 Algebra<Self>
751 + RawDataSerializable
752 + Packable
753 + 'static
754 + Copy
755 + Div<Self, Output = Self>
756 + DivAssign
757 + Add<Self::Packing, Output = Self::Packing>
758 + Sub<Self::Packing, Output = Self::Packing>
759 + Mul<Self::Packing, Output = Self::Packing>
760 + Eq
761 + Hash
762 + Send
763 + Sync
764 + Display
765 + Serialize
766 + DeserializeOwned
767{
768 type Packing: PackedField<Scalar = Self>;
769
770 /// A generator of this field's multiplicative group.
771 const GENERATOR: Self;
772
773 /// Check if the given field element is equal to the unique additive identity (ZERO).
774 #[must_use]
775 #[inline]
776 fn is_zero(&self) -> bool {
777 *self == Self::ZERO
778 }
779
780 /// Check if the given field element is equal to the unique multiplicative identity (ONE).
781 #[must_use]
782 #[inline]
783 fn is_one(&self) -> bool {
784 *self == Self::ONE
785 }
786
787 /// The multiplicative inverse of this field element, if it exists.
788 ///
789 /// NOTE: The inverse of `0` is undefined and will return `None`.
790 #[must_use]
791 fn try_inverse(&self) -> Option<Self>;
792
793 /// The multiplicative inverse of this field element.
794 ///
795 /// # Panics
796 /// The function will panic if the field element is `0`.
797 /// Use try_inverse if you want to handle this case.
798 #[must_use]
799 fn inverse(&self) -> Self {
800 self.try_inverse().expect("Tried to invert zero")
801 }
802
803 /// Add two slices of field elements together, returning the result in the first slice.
804 ///
805 /// Makes use of packing to speed up the addition.
806 ///
807 /// This is optimal for cases where the two slices are small to medium length. E.g. between
808 /// `F::Packing::WIDTH` and roughly however many elements fit in a cache line.
809 ///
810 /// For larger slices, it's likely worthwhile to use parallelization before calling this.
811 /// Similarly if you need to add a large number of slices together, it's best to
812 /// break them into small chunks and call this on the smaller chunks.
813 ///
814 /// # Panics
815 /// The function will panic if the lengths of the two slices are not equal.
816 #[inline]
817 fn add_slices(slice_1: &mut [Self], slice_2: &[Self]) {
818 let (shorts_1, suffix_1) = Self::Packing::pack_slice_with_suffix_mut(slice_1);
819 let (shorts_2, suffix_2) = Self::Packing::pack_slice_with_suffix(slice_2);
820 debug_assert_eq!(shorts_1.len(), shorts_2.len());
821 debug_assert_eq!(suffix_1.len(), suffix_2.len());
822 for (x_1, &x_2) in shorts_1.iter_mut().zip(shorts_2) {
823 *x_1 += x_2;
824 }
825 for (x_1, &x_2) in suffix_1.iter_mut().zip(suffix_2) {
826 *x_1 += x_2;
827 }
828 }
829
830 /// The number of elements in the field.
831 ///
832 /// This will either be prime if the field is a PrimeField or a power of a
833 /// prime if the field is an extension field.
834 #[must_use]
835 fn order() -> BigUint;
836
837 /// The number of bits required to define an element of this field.
838 ///
839 /// Usually due to storage and practical reasons the memory size of
840 /// a field element will be a little larger than bits().
841 #[must_use]
842 #[inline]
843 fn bits() -> usize {
844 Self::order().bits() as usize
845 }
846}
847
848/// A field isomorphic to `ℤ/p` for some prime `p`.
849///
850/// There is a natural map from `ℤ` to `ℤ/p` which sends an integer `r` to its conjugacy class `[r]`.
851/// Canonically, each conjugacy class `[r]` can be represented by the unique integer `s` in `[0, p - 1)`
852/// satisfying `s = r mod p`. This however is often not the most convenient computational representation
853/// and so internal representations of field elements might differ from this and may change over time.
854pub trait PrimeField:
855 Field
856 + Ord
857 + QuotientMap<u8>
858 + QuotientMap<u16>
859 + QuotientMap<u32>
860 + QuotientMap<u64>
861 + QuotientMap<u128>
862 + QuotientMap<usize>
863 + QuotientMap<i8>
864 + QuotientMap<i16>
865 + QuotientMap<i32>
866 + QuotientMap<i64>
867 + QuotientMap<i128>
868 + QuotientMap<isize>
869{
870 /// Return the representative of `value` in canonical form
871 /// which lies in the range `0 <= x < self.order()`.
872 #[must_use]
873 fn as_canonical_biguint(&self) -> BigUint;
874}
875
876/// A prime field `ℤ/p` with order, `p < 2^64`.
877pub trait PrimeField64: PrimeField {
878 const ORDER_U64: u64;
879
880 /// Return the representative of `value` in canonical form
881 /// which lies in the range `0 <= x < ORDER_U64`.
882 #[must_use]
883 fn as_canonical_u64(&self) -> u64;
884
885 /// Convert a field element to a `u64` such that any two field elements
886 /// are converted to the same `u64` if and only if they represent the same value.
887 ///
888 /// This will be the fastest way to convert a field element to a `u64` and
889 /// is intended for use in hashing. It will also be consistent across different targets.
890 #[must_use]
891 #[inline(always)]
892 fn to_unique_u64(&self) -> u64 {
893 // A simple default which is optimal for some fields.
894 self.as_canonical_u64()
895 }
896}
897
898/// A prime field `ℤ/p` with order `p < 2^32`.
899pub trait PrimeField32: PrimeField64 {
900 const ORDER_U32: u32;
901
902 /// Return the representative of `value` in canonical form
903 /// which lies in the range `0 <= x < ORDER_U64`.
904 #[must_use]
905 fn as_canonical_u32(&self) -> u32;
906
907 /// Convert a field element to a `u32` such that any two field elements
908 /// are converted to the same `u32` if and only if they represent the same value.
909 ///
910 /// This will be the fastest way to convert a field element to a `u32` and
911 /// is intended for use in hashing. It will also be consistent across different targets.
912 #[must_use]
913 #[inline(always)]
914 fn to_unique_u32(&self) -> u32 {
915 // A simple default which is optimal for some fields.
916 self.as_canonical_u32()
917 }
918}
919
920/// A field `EF` which is also an algebra over a field `F`.
921///
922/// This provides a couple of convenience methods on top of the
923/// standard methods provided by `Field`, `Algebra<F>` and `BasedVectorSpace<F>`.
924///
925/// It also provides a type which handles packed vectors of extension field elements.
926pub trait ExtensionField<Base: Field>: Field + Algebra<Base> + BasedVectorSpace<Base> {
927 type ExtensionPacking: PackedFieldExtension<Base, Self> + 'static + Copy + Send + Sync;
928
929 /// Determine if the given element lies in the base field.
930 #[must_use]
931 fn is_in_basefield(&self) -> bool;
932
933 /// If the element lies in the base field project it down.
934 /// Otherwise return None.
935 #[must_use]
936 fn as_base(&self) -> Option<Base>;
937}
938
939// Every field is trivially a one dimensional extension over itself.
940impl<F: Field> ExtensionField<F> for F {
941 type ExtensionPacking = F::Packing;
942
943 #[inline]
944 fn is_in_basefield(&self) -> bool {
945 true
946 }
947
948 #[inline]
949 fn as_base(&self) -> Option<F> {
950 Some(*self)
951 }
952}
953
954/// A field which supplies information like the two-adicity of its multiplicative group, and methods
955/// for obtaining two-adic generators.
956pub trait TwoAdicField: Field {
957 /// The number of factors of two in this field's multiplicative group.
958 const TWO_ADICITY: usize;
959
960 /// Returns a generator of the multiplicative group of order `2^bits`.
961 /// Assumes `bits <= TWO_ADICITY`, otherwise the result is undefined.
962 #[must_use]
963 fn two_adic_generator(bits: usize) -> Self;
964}
965
966/// An iterator which returns the powers of a base element `b` shifted by current `c`: `c, c * b, c * b^2, ...`.
967#[derive(Clone, Debug)]
968pub struct Powers<R: PrimeCharacteristicRing> {
969 pub base: R,
970 pub current: R,
971}
972
973impl<R: PrimeCharacteristicRing> Iterator for Powers<R> {
974 type Item = R;
975
976 fn next(&mut self) -> Option<R> {
977 let result = self.current.clone();
978 self.current *= self.base.clone();
979 Some(result)
980 }
981}
982
983impl<R: PrimeCharacteristicRing> Powers<R> {
984 /// Returns an iterator yielding the first `n` powers.
985 #[inline]
986 #[must_use]
987 pub const fn take(self, n: usize) -> BoundedPowers<R> {
988 BoundedPowers { iter: self, n }
989 }
990
991 /// Fills `slice` with the next `slice.len()` powers yielded by the iterator.
992 #[inline]
993 pub fn fill(self, slice: &mut [R]) {
994 slice
995 .iter_mut()
996 .zip(self)
997 .for_each(|(out, next)| *out = next);
998 }
999
1000 /// Wrapper for `self.take(n).collect()`.
1001 #[inline]
1002 #[must_use]
1003 pub fn collect_n(self, n: usize) -> Vec<R> {
1004 self.take(n).collect()
1005 }
1006}
1007
1008impl<F: Field> BoundedPowers<F> {
1009 /// Collect exactly `num_powers` ascending powers of `self.base`, starting at `self.current`.
1010 ///
1011 /// # Details
1012 ///
1013 /// The computation is split evenly amongst available threads, and each chunk is computed
1014 /// using packed fields.
1015 ///
1016 /// # Performance
1017 ///
1018 /// Enable the `parallel` feature to enable parallelization.
1019 #[must_use]
1020 pub fn collect(self) -> Vec<F> {
1021 let num_powers = self.n;
1022
1023 // When num_powers is small, fallback to serial computation
1024 if num_powers < 16 {
1025 return self.take(num_powers).collect();
1026 }
1027
1028 // Allocate buffer storing packed powers, containing at least `num_powers` scalars.
1029 let width = F::Packing::WIDTH;
1030 let num_packed = num_powers.div_ceil(width);
1031 let mut points_packed = F::Packing::zero_vec(num_packed);
1032
1033 // Split computation evenly among threads
1034 let num_threads = current_num_threads().max(1);
1035 let chunk_size = num_packed.div_ceil(num_threads);
1036
1037 // Precompute base for each chunk.
1038 let base = self.iter.base;
1039 let chunk_base = base.exp_u64((chunk_size * width) as u64);
1040 let shift = self.iter.current;
1041
1042 points_packed
1043 .par_chunks_mut(chunk_size)
1044 .enumerate()
1045 .for_each(|(chunk_idx, chunk_slice)| {
1046 // First power in this chunk
1047 let chunk_start = shift * chunk_base.exp_u64(chunk_idx as u64);
1048
1049 // Fill the chunk with packed powers.
1050 F::Packing::packed_shifted_powers(base, chunk_start).fill(chunk_slice);
1051 });
1052
1053 // return the number of requested points, discarding the unused packed powers
1054 // SAFETY: size_of::<F::Packing> always divides size_of::<F::Packing>.
1055 let mut points = unsafe { flatten_to_base(points_packed) };
1056 points.truncate(num_powers);
1057 points
1058 }
1059}
1060
1061/// Same as [`Powers`], but returns a bounded number of powers.
1062#[derive(Clone, Debug)]
1063pub struct BoundedPowers<R: PrimeCharacteristicRing> {
1064 iter: Powers<R>,
1065 n: usize,
1066}
1067
1068impl<R: PrimeCharacteristicRing> Iterator for BoundedPowers<R> {
1069 type Item = R;
1070
1071 fn next(&mut self) -> Option<R> {
1072 (self.n != 0).then(|| {
1073 self.n -= 1;
1074 self.iter.next().unwrap()
1075 })
1076 }
1077}