Skip to main content

risc0_core/field/
mod.rs

1// Copyright 2026 RISC Zero, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Finite field types and operations
16//!
17//! Defines base fields and extension fields used for finite field-based
18//! operations across the RISC Zero zkVM architecture
19
20use alloc::vec::Vec;
21use bytemuck::checked::CheckedCastError;
22use core::{cmp, fmt::Debug, ops};
23
24pub mod baby_bear;
25
26/// A pair of fields, one of which is an extension field of the other.
27pub trait Field {
28    /// An element of the base field
29    type Elem: Elem + RootsOfUnity;
30    /// An element of the extension field
31    type ExtElem: ExtElem<SubElem = Self::Elem>;
32}
33
34/// Subfield elements that can be compared, copied, and operated
35/// on via multiplication, addition, and subtraction
36pub trait Elem: 'static
37    + Clone
38    + Copy
39    + Send
40    + Sync
41    + Debug
42    + Sized
43    + ops::Neg<Output = Self>
44    + ops::SubAssign
45    + cmp::PartialEq
46    + cmp::Eq
47    + core::clone::Clone
48    + core::marker::Copy
49    + bytemuck::NoUninit
50    + bytemuck::CheckedBitPattern
51    + core::default::Default
52    // Operators for Elem (op) Elem -> Elem
53    + ops::Add<Self, Output = Self>
54    + ops::Sub<Self, Output = Self>
55    + ops::Mul<Self, Output = Self>
56    // Operators for Elem (op)= Elem
57    + ops::AddAssign<Self>
58    + ops::SubAssign<Self>
59    + ops::MulAssign<Self>
60{
61    /// Invalid, a value that is not a member of the field.  This
62    /// should only be used with the "is_valid" or "unwrap_or_zero"
63    /// methods.
64    const INVALID: Self;
65
66    /// Zero, the additive identity.
67    const ZERO: Self;
68
69    /// One, the multiplicative identity.
70    const ONE: Self;
71
72    /// How many u32 words are required to hold a single element
73    const WORDS: usize;
74
75    /// Compute the multiplicative inverse of `x` (or `1 / x` in finite field
76    /// terms).
77    fn inv(self) -> Self;
78
79    /// Return an element raised to the given power.
80    fn pow(self, exp: usize) -> Self {
81        debug_assert!(self.is_valid());
82        let mut n = exp;
83        let mut tot = Self::ONE;
84        let mut x = self;
85        while n != 0 {
86            if n % 2 == 1 {
87                tot *= x;
88            }
89            n /= 2;
90            x *= x;
91        }
92        tot
93    }
94
95    /// Returns a random valid field element.
96    fn random(rng: &mut impl rand_core::RngCore) -> Self;
97
98    /// Import a number into the field from the natural numbers.
99    fn from_u64(val: u64) -> Self;
100
101    /// Represent a field element as a sequence of u32s
102    fn to_u32_words(&self) -> Vec<u32>;
103
104    /// Interpret a sequence of u32s as a field element
105    fn from_u32_words(val: &[u32]) -> Self;
106
107    /// Returns true if this element is not INVALID.  Unlike most
108    /// methods, this may be called on an INVALID element.
109    fn is_valid(&self) -> bool;
110
111    /// Returns true if this element is represented in reduced/normalized form.
112    /// Every element has exactly one reduced form. For a field of prime order
113    /// P, this typically means the underlying data is < P, and for an extension
114    /// field, this typically means every component is in reduced form.
115    fn is_reduced(&self) -> bool;
116
117    /// Returns 0 if this element is INVALID, else the value of this
118    /// element.  Unlike most methods, this may be called on an
119    /// INVALID element.
120    fn valid_or_zero(&self) -> Self {
121        if self.is_valid() {
122            *self
123        } else {
124            Self::ZERO
125        }
126    }
127
128    /// Returns this element, but checks to make sure it's valid.
129    fn ensure_valid(&self) -> &Self {
130        debug_assert!(self.is_valid());
131        self
132    }
133
134    /// Returns this element, but checks to make sure it's in reduced form.
135    fn ensure_reduced(&self) -> &Self {
136        assert!(self.is_reduced());
137        self
138    }
139
140    /// Interprets a slice of these elements as u32s.  These elements
141    /// may not be INVALID.
142    fn as_u32_slice(elems: &[Self]) -> &[u32] {
143        if cfg!(debug_assertions) {
144            for elem in elems {
145                elem.ensure_valid();
146            }
147        }
148        Self::as_u32_slice_unchecked(elems)
149    }
150
151    /// Interprets a slice of these elements as u32s.  These elements
152    /// may potentially be INVALID.
153    fn as_u32_slice_unchecked(elems: &[Self]) -> &[u32] {
154        bytemuck::cast_slice(elems)
155    }
156
157    /// Interprets a slice of u32s as a slice of these elements.
158    /// These elements may not be INVALID.
159    fn from_u32_slice(u32s: &[u32]) -> &[Self] {
160        bytemuck::checked::cast_slice(u32s)
161    }
162
163    /// Interprets a slice of u32s as a slice of these elements.
164    /// These elements may not be INVALID.
165    fn try_from_u32_slice(u32s: &[u32]) -> Result<&[Self], CheckedCastError> {
166        bytemuck::checked::try_cast_slice(u32s)
167    }
168}
169
170/// A field extension which can be constructed from a subfield element [Elem]
171///
172/// Represents an element of an extension field. This extension field is
173/// associated with a base field (sometimes called "subfield") whose element
174/// type is given by the generic type parameter.
175pub trait ExtElem : Elem
176    + From<Self::SubElem>
177    + ops::Neg<Output = Self>
178    + cmp::PartialEq
179    + cmp::Eq
180
181    // Operators for ExtElem (op) Elem -> ExtElem
182    + ops::Add<Self::SubElem, Output = Self>
183    + ops::Sub<Self::SubElem, Output = Self>
184    + ops::Mul<Self::SubElem, Output = Self>
185
186    // Operators for ExtElem (op)= Elem
187    + ops::AddAssign<Self::SubElem>
188    + ops::SubAssign<Self::SubElem>
189    + ops::MulAssign<Self::SubElem>
190{
191    /// An element of the base field
192    ///
193    /// This type represents an element of the base field (sometimes called
194    /// "subfield") of this extension field.
195    type SubElem: Elem
196        // Operators for Elem (op) ExtElem -> ExtElem
197        + ops::Add<Self, Output = Self>
198        + ops::Sub<Self, Output = Self>
199        + ops::Mul<Self, Output = Self>;
200
201    /// The degree of the field extension
202    ///
203    /// This the degree of the extension field when interpreted as a vector
204    /// space over the base field. Thus, an [ExtElem] can be represented as
205    /// `EXT_SIZE` [SubElem](ExtElem::SubElem)s.
206    const EXT_SIZE: usize;
207
208    /// Interpret a base field element as an extension field element
209    ///
210    /// Every [SubElem](ExtElem::SubElem) is (mathematically) an [ExtElem]. This
211    /// constructs the [ExtElem] equal to the given [SubElem](ExtElem::SubElem).
212    fn from_subfield(elem: &Self::SubElem) -> Self;
213
214    /// Construct an extension field element
215    ///
216    /// Construct an extension field element from a (mathematical) vector of
217    /// [SubElem](ExtElem::SubElem)s. This vector is length
218    /// [EXT_SIZE](ExtElem::EXT_SIZE).
219    fn from_subelems(elems: impl IntoIterator<Item = Self::SubElem>) -> Self;
220
221    /// Express an extension field element in terms of base field elements
222    ///
223    /// Returns the (mathematical) vector of [SubElem](ExtElem::SubElem)s equal
224    /// to the [ExtElem]. This vector is length [EXT_SIZE](ExtElem::EXT_SIZE).
225    fn subelems(&self) -> &[Self::SubElem];
226}
227
228/// Roots of unity for the field whose elements are represented by [ExtElem] and
229/// whose subfield elements are represented by [Elem]
230pub trait RootsOfUnity: Sized + 'static {
231    /// Maximum root of unity which is a power of 2 (i.e., there is a
232    /// 2^MAX_ROU_PO2th root of unity, but no 2^(MAX_ROU_PO2+1)th root.
233    const MAX_ROU_PO2: usize;
234
235    /// For each power of 2, the 'forward' root of unity for
236    /// the po2.  That is, this list satisfies ROU_FWD\[i+1\] ^ 2 =
237    /// ROU_FWD\[i\] in the prime field, which implies ROU_FWD\[i\] ^
238    /// (2 ^ i) = 1.
239    const ROU_FWD: &'static [Self];
240
241    /// For each power of 2, the 'reverse' root of unity for
242    /// the po2.  This list satisfies ROU_FWD\[i\] * ROU_REV\[i\] = 1
243    /// in the prime field F_2013265921.
244    const ROU_REV: &'static [Self];
245}
246
247/// Equivalent to exponents.map(|exponent|
248/// base.pow(exponent)).collect(), but optimized to execute fewer
249/// multiplies.  Exponents must be sorted and strictly increasing.
250pub fn map_pow<E: super::field::Elem>(base: E, exponents: &[usize]) -> Vec<E> {
251    let mut result = Vec::with_capacity(exponents.len());
252
253    let mut prev_exp: usize;
254    match exponents.first() {
255        None => return result,
256        Some(&exp) => {
257            result.push(base.pow(exp));
258            prev_exp = exp;
259        }
260    }
261
262    for exp in exponents.iter().skip(1).copied() {
263        assert!(
264            prev_exp < exp,
265            "Expecting exponents to be strictly increasing but {prev_exp} is not less than {exp}"
266        );
267        if exp == prev_exp + 1 {
268            result.push(*result.last().unwrap() * base);
269        } else {
270            result.push(*result.last().unwrap() * base.pow(exp - prev_exp));
271        }
272        prev_exp = exp;
273    }
274
275    result
276}
277
278#[cfg(test)]
279mod tests {
280    use core::fmt::Debug;
281
282    use rand::Rng;
283
284    use super::{Elem, ExtElem, RootsOfUnity};
285
286    pub fn test_roots_of_unity<F: Elem + RootsOfUnity + Debug>() {
287        let mut cur: Option<F> = None;
288
289        for &rou in F::ROU_FWD.iter().rev() {
290            if let Some(ref mut curval) = &mut cur {
291                *curval *= *curval;
292                assert_eq!(*curval, rou);
293            } else {
294                cur = Some(rou);
295            }
296        }
297        assert_eq!(cur, Some(F::ONE));
298
299        for (&fwd, &rev) in F::ROU_FWD.iter().zip(F::ROU_REV.iter()) {
300            assert_eq!(fwd * rev, F::ONE);
301        }
302    }
303
304    fn non_zero_rand<F: Elem>(r: &mut impl Rng) -> F {
305        loop {
306            let val = F::random(r);
307            if val != F::ZERO {
308                return val;
309            }
310        }
311    }
312    pub fn test_field_ops<F>(p_u64: u64)
313    where
314        F: Elem + Into<u64> + From<u64> + Debug,
315    {
316        // For testing, we do 128-bit arithmetic so we don't have to worry about
317        // overflows.
318        let p: u128 = p_u64 as _;
319
320        assert_eq!(F::from(0), F::ZERO);
321        assert_eq!(F::from(p_u64), F::ZERO);
322        assert_eq!(F::from(1), F::ONE);
323        assert_eq!(F::from(p_u64 - 1) + F::from(1), F::ZERO);
324
325        assert_eq!(F::ZERO.inv(), F::ZERO);
326        assert_eq!(F::ONE.inv(), F::ONE);
327
328        // Compare against many randomly generated numbers to make sure results match
329        // the expected results for regular modular arithmetic.
330        let mut rng = rand::rng();
331
332        for _ in 0..1000 {
333            let x: F = non_zero_rand(&mut rng);
334            let y: F = non_zero_rand(&mut rng);
335
336            let xi: u128 = x.into() as _;
337            let yi: u128 = y.into() as _;
338
339            assert_eq!((x + y).into() as u128, (xi + yi) % p);
340            assert_eq!((x * y).into() as u128, (xi * yi) % p);
341            assert_eq!((x - y).into() as u128, (xi + p - yi) % p);
342
343            let xinv = x.inv();
344            if x != F::ONE {
345                assert!(xinv != x);
346            }
347            assert_eq!(xinv * x, F::ONE);
348        }
349
350        // Make sure map_pow produces the same results as calling F::pow.
351        let base: F = non_zero_rand(&mut rng);
352        let map_pow_cases: &[&[usize]] = &[&[], &[0], &[0, 1, 2, 3], &[1, 18, 19, 1234, 5678]];
353        for exps in map_pow_cases.iter() {
354            let expected: alloc::vec::Vec<_> = exps.iter().map(|&exp| base.pow(exp)).collect();
355            let actual = super::map_pow(base, exps);
356            assert_eq!(expected, actual);
357        }
358    }
359
360    /// Make sure extension field operations are consistent, no matter
361    /// what order they use, and whether they promote from base
362    /// elements or not.
363    pub fn test_ext_field_ops<E: ExtElem>() {
364        let mut r = rand::rng();
365        let x = E::random(&mut r);
366        let y = E::random(&mut r);
367
368        let mut e = x;
369
370        // Promote E to the extended field.
371        let promote = |e| E::from(e);
372
373        // Addition and subtraction operations between two ExtElems
374        e += y;
375        assert_eq!(e, x + y);
376        assert_eq!(e, y + x);
377        assert_eq!(x, e - y);
378        assert_eq!(-x, y - e);
379        e -= y;
380        assert_eq!(e, x);
381
382        // Multiplication and inverse operations between two ExtElems
383        e *= y;
384        assert_eq!(e, x * y);
385        assert_eq!(e, y * x);
386        assert_eq!(x, e * y.inv());
387        assert_eq!(x.inv(), y * e.inv());
388        e *= y.inv();
389        assert_eq!(e, x);
390
391        // Addition and subtraction between an ExtElem and a base element
392        let b = E::SubElem::random(&mut r);
393        e += b;
394        assert_eq!(e, x + b);
395        assert_eq!(e, b + x);
396        assert_eq!(e, x + promote(b));
397        assert_eq!(x, e - promote(b));
398        assert_eq!(x, e - b);
399        assert_eq!(-x, b - e);
400        assert_eq!(-x, promote(b) - e);
401        e -= b;
402        assert_eq!(e, x);
403
404        // Multiplication and inverse operations between an ExtElem and a base element
405        e *= b;
406        assert_eq!(e, x * b);
407        assert_eq!(e, b * x);
408        assert_eq!(e, x * promote(b));
409        assert_eq!(x, e * b.inv());
410        assert_eq!(x, b.inv() * e);
411        assert_eq!(x, e * promote(b.inv()));
412        assert_eq!(x, e * promote(b).inv());
413        assert_eq!(x.inv(), b * e.inv());
414        e *= b.inv();
415        assert_eq!(e, x);
416    }
417}