miden-crypto/src/dsa/rpo_falcon512/math/field.rs
src/dsa/rpo_falcon512/math/field.rsRaw
1use super::{fft::CyclotomicFourier, Inverse, MODULUS};
2use alloc::string::String;
3use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4use num::{One, Zero};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub struct FalconFelt(u32);
8
9impl FalconFelt {
10 pub const fn new(value: i16) -> Self {
11 let gtz_bool = value >= 0;
12 let gtz_int = gtz_bool as i16;
13 let gtz_sign = gtz_int - ((!gtz_bool) as i16);
14 let reduced = gtz_sign * (gtz_sign * value) % MODULUS;
15 let canonical_representative = (reduced + MODULUS * (1 - gtz_int)) as u32;
16 FalconFelt(canonical_representative)
17 }
18
19 pub const fn value(&self) -> i16 {
20 self.0 as i16
21 }
22
23 pub fn balanced_value(&self) -> i16 {
24 let value = self.value();
25 let g = (value > ((MODULUS) / 2)) as i16;
26 value - (MODULUS) * g
27 }
28
29 pub const fn multiply(&self, other: Self) -> Self {
30 FalconFelt((self.0 * other.0) % MODULUS as u32)
31 }
32}
33
34impl Add for FalconFelt {
35 type Output = Self;
36
37 #[allow(clippy::suspicious_arithmetic_impl)]
38 fn add(self, rhs: Self) -> Self::Output {
39 let (s, _) = self.0.overflowing_add(rhs.0);
40 let (d, n) = s.overflowing_sub(MODULUS as u32);
41 let (r, _) = d.overflowing_add(MODULUS as u32 * (n as u32));
42 FalconFelt(r)
43 }
44}
45
46impl AddAssign for FalconFelt {
47 fn add_assign(&mut self, rhs: Self) {
48 *self = *self + rhs;
49 }
50}
51
52impl Sub for FalconFelt {
53 type Output = Self;
54
55 fn sub(self, rhs: Self) -> Self::Output {
56 self + -rhs
57 }
58}
59
60impl SubAssign for FalconFelt {
61 fn sub_assign(&mut self, rhs: Self) {
62 *self = *self - rhs;
63 }
64}
65
66impl Neg for FalconFelt {
67 type Output = FalconFelt;
68
69 fn neg(self) -> Self::Output {
70 let is_nonzero = self.0 != 0;
71 let r = MODULUS as u32 - self.0;
72 FalconFelt(r * (is_nonzero as u32))
73 }
74}
75
76impl Mul for FalconFelt {
77 fn mul(self, rhs: Self) -> Self::Output {
78 FalconFelt((self.0 * rhs.0) % MODULUS as u32)
79 }
80
81 type Output = Self;
82}
83
84impl MulAssign for FalconFelt {
85 fn mul_assign(&mut self, rhs: Self) {
86 *self = *self * rhs;
87 }
88}
89
90impl Div for FalconFelt {
91 type Output = FalconFelt;
92
93 #[allow(clippy::suspicious_arithmetic_impl)]
94 fn div(self, rhs: Self) -> Self::Output {
95 self * rhs.inverse_or_zero()
96 }
97}
98
99impl DivAssign for FalconFelt {
100 fn div_assign(&mut self, rhs: Self) {
101 *self = *self / rhs
102 }
103}
104
105impl Zero for FalconFelt {
106 fn zero() -> Self {
107 FalconFelt::new(0)
108 }
109
110 fn is_zero(&self) -> bool {
111 self.0 == 0
112 }
113}
114
115impl One for FalconFelt {
116 fn one() -> Self {
117 FalconFelt::new(1)
118 }
119}
120
121impl Inverse for FalconFelt {
122 fn inverse_or_zero(self) -> Self {
123 // q-2 = 0b10 11 11 11 11 11 11
124 let two = self.multiply(self);
125 let three = two.multiply(self);
126 let six = three.multiply(three);
127 let twelve = six.multiply(six);
128 let fifteen = twelve.multiply(three);
129 let thirty = fifteen.multiply(fifteen);
130 let sixty = thirty.multiply(thirty);
131 let sixty_three = sixty.multiply(three);
132
133 let sixty_three_sq = sixty_three.multiply(sixty_three);
134 let sixty_three_qu = sixty_three_sq.multiply(sixty_three_sq);
135 let sixty_three_oc = sixty_three_qu.multiply(sixty_three_qu);
136 let sixty_three_hx = sixty_three_oc.multiply(sixty_three_oc);
137 let sixty_three_tt = sixty_three_hx.multiply(sixty_three_hx);
138 let sixty_three_sf = sixty_three_tt.multiply(sixty_three_tt);
139
140 let all_ones = sixty_three_sf.multiply(sixty_three);
141 let two_e_twelve = all_ones.multiply(self);
142 let two_e_thirteen = two_e_twelve.multiply(two_e_twelve);
143
144 two_e_thirteen.multiply(all_ones)
145 }
146}
147
148impl CyclotomicFourier for FalconFelt {
149 fn primitive_root_of_unity(n: usize) -> Self {
150 let log2n = n.ilog2();
151 assert!(log2n <= 12);
152 // and 1331 is a twelfth root of unity
153 let mut a = FalconFelt::new(1331);
154 let num_squarings = 12 - n.ilog2();
155 for _ in 0..num_squarings {
156 a *= a;
157 }
158 a
159 }
160}
161
162impl TryFrom<u32> for FalconFelt {
163 type Error = String;
164
165 fn try_from(value: u32) -> Result<Self, Self::Error> {
166 if value >= MODULUS as u32 {
167 Err(format!("value {value} is greater than or equal to the field modulus {MODULUS}"))
168 } else {
169 Ok(FalconFelt::new(value as i16))
170 }
171 }
172}