stwo_gpu/core/fields/
m31.rs1use core::fmt::Display;
2use core::ops::{
3 Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
4};
5
6use bytemuck::{Pod, Zeroable};
7use rand::distributions::{Distribution, Standard};
8use serde::{Deserialize, Serialize};
9
10use super::{ComplexConjugate, FieldExpOps};
11use crate::impl_field;
12pub const MODULUS_BITS: u32 = 31;
13pub const N_BYTES_FELT: usize = 4;
14pub const P: u32 = 2147483647; #[repr(transparent)]
17#[derive(
18 Copy,
19 Clone,
20 Debug,
21 Default,
22 PartialEq,
23 Eq,
24 PartialOrd,
25 Ord,
26 Hash,
27 Pod,
28 Zeroable,
29 Serialize,
30 Deserialize,
31)]
32pub struct M31(pub u32);
33pub type BaseField = M31;
34
35impl_field!(M31, P);
36
37impl M31 {
38 pub fn partial_reduce(val: u32) -> Self {
47 Self(val.checked_sub(P).unwrap_or(val))
48 }
49
50 pub const fn reduce(val: u64) -> Self {
59 Self((((((val >> MODULUS_BITS) + val + 1) >> MODULUS_BITS) + val) & (P as u64)) as u32)
60 }
61
62 pub const fn from_u32_unchecked(arg: u32) -> Self {
63 Self(arg)
64 }
65
66 pub fn inverse(&self) -> Self {
67 assert!(!self.is_zero(), "0 has no inverse");
68 pow2147483645(*self)
69 }
70}
71
72impl Display for M31 {
73 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74 write!(f, "{}", self.0)
75 }
76}
77
78impl Add for M31 {
79 type Output = Self;
80
81 fn add(self, rhs: Self) -> Self::Output {
82 Self::partial_reduce(self.0 + rhs.0)
83 }
84}
85
86impl Neg for M31 {
87 type Output = Self;
88
89 fn neg(self) -> Self::Output {
90 Self::partial_reduce(P - self.0)
91 }
92}
93
94impl Sub for M31 {
95 type Output = Self;
96
97 fn sub(self, rhs: Self) -> Self::Output {
98 Self::partial_reduce(self.0 + P - rhs.0)
99 }
100}
101
102impl Mul for M31 {
103 type Output = Self;
104
105 fn mul(self, rhs: Self) -> Self::Output {
106 Self::reduce((self.0 as u64) * (rhs.0 as u64))
107 }
108}
109
110impl FieldExpOps for M31 {
111 fn inverse(&self) -> Self {
120 self.inverse()
121 }
122}
123
124impl ComplexConjugate for M31 {
125 fn complex_conjugate(&self) -> Self {
126 *self
127 }
128}
129
130impl One for M31 {
131 fn one() -> Self {
132 Self(1)
133 }
134}
135
136impl Zero for M31 {
137 fn zero() -> Self {
138 Self(0)
139 }
140
141 fn is_zero(&self) -> bool {
142 *self == Self::zero()
143 }
144}
145
146impl From<usize> for M31 {
147 fn from(value: usize) -> Self {
148 M31::reduce(value.try_into().unwrap())
149 }
150}
151
152impl From<u32> for M31 {
153 fn from(value: u32) -> Self {
154 M31::reduce(value.into())
155 }
156}
157
158impl From<i32> for M31 {
159 fn from(value: i32) -> Self {
160 if value < 0 {
161 const P2: u64 = 2 * P as u64;
162 return M31::reduce(P2 - value.unsigned_abs() as u64);
163 }
164
165 M31::reduce(value.unsigned_abs() as u64)
166 }
167}
168
169impl Distribution<M31> for Standard {
170 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> M31 {
172 M31(rng.gen_range(0..P))
173 }
174}
175
176#[cfg(test)]
177#[macro_export]
178macro_rules! m31 {
179 ($m:expr) => {
180 $crate::core::fields::m31::M31::from_u32_unchecked($m)
181 };
182}
183
184pub fn pow2147483645<T: FieldExpOps>(v: T) -> T {
198 let t0 = sqn::<2, T>(v.clone()) * v.clone();
199 let t1 = sqn::<1, T>(t0.clone()) * t0.clone();
200 let t2 = sqn::<3, T>(t1.clone()) * t0.clone();
201 let t3 = sqn::<1, T>(t2.clone()) * t0.clone();
202 let t4 = sqn::<8, T>(t3.clone()) * t3.clone();
203 let t5 = sqn::<8, T>(t4.clone()) * t3.clone();
204 sqn::<7, T>(t5) * t2
205}
206
207fn sqn<const N: usize, T: FieldExpOps>(mut v: T) -> T {
209 for _ in 0..N {
210 v = v.square();
211 }
212 v
213}
214
215#[cfg(test)]
216mod tests {
217 use rand::rngs::SmallRng;
218 use rand::{Rng, SeedableRng};
219
220 use super::{M31, P};
221
222 const fn mul_p(a: u32, b: u32) -> u32 {
223 ((a as u64 * b as u64) % P as u64) as u32
224 }
225
226 const fn add_p(a: u32, b: u32) -> u32 {
227 (a + b) % P
228 }
229
230 const fn neg_p(a: u32) -> u32 {
231 if a == 0 {
232 0
233 } else {
234 P - a
235 }
236 }
237
238 #[test]
239 fn test_basic_ops() {
240 let mut rng = SmallRng::seed_from_u64(0);
241 for _ in 0..10000 {
242 let x: u32 = rng.gen::<u32>() % P;
243 let y: u32 = rng.gen::<u32>() % P;
244 assert_eq!(m31!(add_p(x, y)), m31!(x) + m31!(y));
245 assert_eq!(m31!(mul_p(x, y)), m31!(x) * m31!(y));
246 assert_eq!(m31!(neg_p(x)), -m31!(x));
247 }
248 }
249
250 #[test]
251 fn test_m31_from_i32() {
252 assert_eq!(M31::from(-1_i32), M31::from(P - 1));
253 assert_eq!(M31::from(-10_i32), M31::from(P - 10));
254 assert_eq!(M31::from(1_i32), M31::from(1));
255 assert_eq!(M31::from(10_i32), M31::from(10));
256 }
257}