1use core::ops;
18
19use bytemuck::{Pod, Zeroable};
20use rand::Rng;
21
22use crate::Random;
23
24pub const P: u32 = 15 * (1 << 27) + 1;
26pub const P_U64: u64 = P as u64;
28
29#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Zeroable, Pod)]
49#[repr(transparent)]
50pub struct Fp(u32);
51
52impl Fp {
53 pub const fn new(x: u32) -> Self {
55 Self(x)
56 }
57
58 pub fn max() -> Self {
60 Self(P - 1)
61 }
62
63 pub fn pow(self, n: usize) -> Self {
65 let mut n = n;
66 let mut tot = Fp(1);
67 let mut x = self;
68 while n != 0 {
69 if n % 2 == 1 {
70 tot *= x;
71 }
72 n = n / 2;
73 x *= x;
74 }
75 tot
76 }
77
78 pub fn inv(self) -> Self {
86 self.pow((P - 2) as usize)
87 }
88}
89
90pub trait FpMul {
92 fn fp_mul(self, x: Fp) -> Self;
94}
95
96impl FpMul for Fp {
97 fn fp_mul(self, x: Fp) -> Self {
98 self * x
99 }
100}
101
102impl Random for Fp {
103 fn random<R: Rng>(rng: &mut R) -> Self {
104 const REJECT_CUTOFF: u32 = (u32::MAX / P) * P;
107 let mut val: u32 = rng.gen();
108
109 while val >= REJECT_CUTOFF {
110 val = rng.gen();
111 }
112 Fp::from(val)
113 }
114}
115
116impl ops::Add for Fp {
117 type Output = Self;
118 fn add(self, rhs: Self) -> Self {
119 Fp(add(self.0, rhs.0))
120 }
121}
122
123impl ops::AddAssign for Fp {
124 fn add_assign(&mut self, rhs: Self) {
125 self.0 = add(self.0, rhs.0)
126 }
127}
128
129impl ops::Sub for Fp {
130 type Output = Self;
131 fn sub(self, rhs: Self) -> Self {
132 Fp(sub(self.0, rhs.0))
133 }
134}
135
136impl ops::SubAssign for Fp {
137 fn sub_assign(&mut self, rhs: Self) {
138 self.0 = sub(self.0, rhs.0)
139 }
140}
141
142impl ops::Mul for Fp {
143 type Output = Self;
144 fn mul(self, rhs: Self) -> Self {
145 Fp(mul(self.0, rhs.0))
146 }
147}
148
149impl ops::MulAssign for Fp {
150 fn mul_assign(&mut self, rhs: Self) {
151 self.0 = mul(self.0, rhs.0)
152 }
153}
154
155impl ops::Neg for Fp {
156 type Output = Self;
157 fn neg(self) -> Self {
158 Fp(0) - self
159 }
160}
161
162impl From<Fp> for u32 {
163 fn from(x: Fp) -> Self {
164 x.0
165 }
166}
167
168impl From<&Fp> for u32 {
169 fn from(x: &Fp) -> Self {
170 x.0
171 }
172}
173
174impl From<Fp> for u64 {
175 fn from(x: Fp) -> Self {
176 x.0.into()
177 }
178}
179
180impl From<u32> for Fp {
181 fn from(x: u32) -> Self {
182 Fp(x % P)
183 }
184}
185
186impl From<u64> for Fp {
187 fn from(x: u64) -> Self {
188 Fp((x % P_U64) as u32)
189 }
190}
191
192fn add(lhs: u32, rhs: u32) -> u32 {
193 let x = lhs + rhs;
194 return if x >= P { x - P } else { x };
195}
196
197fn sub(lhs: u32, rhs: u32) -> u32 {
198 let x = lhs.wrapping_sub(rhs);
199 return if x > P { x.wrapping_add(P) } else { x };
200}
201
202fn mul(lhs: u32, rhs: u32) -> u32 {
203 (((lhs as u64) * (rhs as u64)) % P_U64) as u32
204}
205
206#[cfg(test)]
207mod tests {
208 use super::{Fp, P, P_U64};
209 use crate::Random;
210 use rand::SeedableRng;
211
212 #[test]
213 fn inv() {
214 assert_eq!(Fp(5).inv() * Fp(5), Fp(1));
216 }
217
218 #[test]
219 fn pow() {
220 assert_eq!(Fp(5).pow(0), Fp(1));
222 assert_eq!(Fp(5).pow(1), Fp(5));
223 assert_eq!(Fp(5).pow(2), Fp(25));
224 assert_eq!(Fp(5).pow(1000), Fp(589699054));
226 assert_eq!(Fp(5).pow((P - 2) as usize) * Fp(5), Fp(1));
227 assert_eq!(Fp(5).pow((P - 1) as usize), Fp(1));
228 }
229
230 #[test]
231 fn compare_native() {
232 let mut rng = rand::rngs::SmallRng::seed_from_u64(2);
234 for _ in 0..100_000 {
235 let fa = Fp::random(&mut rng);
236 let fb = Fp::random(&mut rng);
237 let a: u64 = fa.into();
238 let b: u64 = fb.into();
239 assert_eq!(fa + fb, Fp::from(a + b));
240 assert_eq!(fa - fb, Fp::from(a + (P_U64 - b)));
241 assert_eq!(fa * fb, Fp::from(a * b));
242 }
243 }
244}