binius_field/
field.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use std::{
4	fmt::{Debug, Display},
5	hash::Hash,
6	iter::{Product, Sum},
7	ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
8};
9
10use binius_utils::{DeserializeBytes, SerializeBytes};
11
12use crate::{
13	Random,
14	arithmetic_traits::{InvertOrZero, Square},
15	as_packed_field::PackScalar,
16	underlier::WithUnderlier,
17};
18
19/// This trait is based on `ff::Field` with some unused functionality removed.
20pub trait Field:
21	Sized
22	+ Eq
23	+ Copy
24	+ Clone
25	+ Default
26	+ Send
27	+ Sync
28	+ Debug
29	+ Display
30	+ Hash
31	+ 'static
32	+ Neg<Output = Self>
33	+ Add<Output = Self>
34	+ Sub<Output = Self>
35	+ Mul<Output = Self>
36	+ Sum
37	+ Product
38	+ for<'a> Add<&'a Self, Output = Self>
39	+ for<'a> Sub<&'a Self, Output = Self>
40	+ for<'a> Mul<&'a Self, Output = Self>
41	+ for<'a> Sum<&'a Self>
42	+ for<'a> Product<&'a Self>
43	+ AddAssign
44	+ SubAssign
45	+ MulAssign
46	+ for<'a> AddAssign<&'a Self>
47	+ for<'a> SubAssign<&'a Self>
48	+ for<'a> MulAssign<&'a Self>
49	+ Square
50	+ InvertOrZero
51	+ Random
52	// `Underlier: PackScalar<Self>` is an obvious property but it can't be deduced by the compiler so we are id here.
53	+ WithUnderlier<Underlier: PackScalar<Self>>
54	+ SerializeBytes
55	+ DeserializeBytes
56{
57	/// The zero element of the field, the additive identity.
58	const ZERO: Self;
59
60	/// The one element of the field, the multiplicative identity.
61	const ONE: Self;
62
63	/// The characteristic of the field.
64	const CHARACTERISTIC: usize;
65
66	/// Returns true iff this element is zero.
67	fn is_zero(&self) -> bool {
68		*self == Self::ZERO
69	}
70
71	/// Doubles this element.
72	#[must_use]
73	fn double(&self) -> Self;
74
75	/// Computes the multiplicative inverse of this element,
76	/// failing if the element is zero.
77	fn invert(&self) -> Option<Self> {
78		let inv = self.invert_or_zero();
79		(!inv.is_zero()).then_some(inv)
80	}
81
82	/// Exponentiates `self` by `exp`, where `exp` is a little-endian order integer
83	/// exponent.
84	///
85	/// # Guarantees
86	///
87	/// This operation is constant time with respect to `self`, for all exponents with the
88	/// same number of digits (`exp.as_ref().len()`). It is variable time with respect to
89	/// the number of digits in the exponent.
90	fn pow<S: AsRef<[u64]>>(&self, exp: S) -> Self {
91		let mut res = Self::ONE;
92		for e in exp.as_ref().iter().rev() {
93			for i in (0..64).rev() {
94				res = res.square();
95				let mut tmp = res;
96				tmp *= self;
97				if ((*e >> i) & 1) != 0 {
98					res = tmp;
99				}
100			}
101		}
102		res
103	}
104
105	/// Exponentiates `self` by `exp`, where `exp` is a little-endian order integer
106	/// exponent.
107	///
108	/// # Guarantees
109	///
110	/// **This operation is variable time with respect to `self`, for all exponent.** If
111	/// the exponent is fixed, this operation is effectively constant time. However, for
112	/// stronger constant-time guarantees, [`Field::pow`] should be used.
113	fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
114		let mut res = Self::ONE;
115		for e in exp.as_ref().iter().rev() {
116			for i in (0..64).rev() {
117				res = res.square();
118
119				if ((*e >> i) & 1) == 1 {
120					res.mul_assign(self);
121				}
122			}
123		}
124
125		res
126	}
127}