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}