1#[macro_export]
10macro_rules! fiat_monty_field_arithmetic {
11 (
12 name: $fe:tt,
13 params: $params:ty,
14 uint: $uint:ty,
15 non_mont: $non_mont_type:expr,
16 mont: $mont_type:expr,
17 from_mont: $from_mont:ident,
18 to_mont: $to_mont:ident,
19 add: $add:ident,
20 sub: $sub:ident,
21 mul: $mul:ident,
22 neg: $neg:ident,
23 square: $square:ident,
24 divstep_precomp: $divstep_precomp:ident,
25 divstep: $divstep:ident,
26 msat: $msat:ident,
27 selectnz: $selectznz:ident
28 ) => {
29 impl $fe {
30 #[doc = stringify!($fe)]
32 #[doc = stringify!($uint)]
34 #[inline]
40 pub(crate) const fn from_uint_unchecked(w: $uint) -> Self {
41 let mut out = $mont_type([0; <$uint>::LIMBS]);
42 $to_mont(&mut out, &$non_mont_type(w.to_words()));
43 Self(
44 $crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
45 out.0,
46 ),
47 )
48 }
49
50 #[doc = stringify!($fe)]
52 #[doc = stringify!($uint)]
54 #[inline]
56 pub const fn to_canonical(self) -> $uint {
57 let mut out = $non_mont_type([0; <$uint>::LIMBS]);
58 $from_mont(&mut out, &$mont_type(self.0.to_montgomery_words()));
59 <$uint>::from_words(out.0)
60 }
61
62 #[inline]
64 pub const fn add(&self, rhs: &Self) -> Self {
65 let mut out = $mont_type([0; <$uint>::LIMBS]);
66 $add(
67 &mut out,
68 &$mont_type(self.0.to_montgomery_words()),
69 &$mont_type(rhs.0.to_montgomery_words()),
70 );
71 Self(
72 $crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
73 out.0,
74 ),
75 )
76 }
77
78 #[inline]
80 #[must_use]
81 pub const fn double(&self) -> Self {
82 self.add(self)
83 }
84
85 #[inline]
87 pub const fn sub(&self, rhs: &Self) -> Self {
88 let mut out = $mont_type([0; <$uint>::LIMBS]);
89 $sub(
90 &mut out,
91 &$mont_type(self.0.to_montgomery_words()),
92 &$mont_type(rhs.0.to_montgomery_words()),
93 );
94 Self(
95 $crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
96 out.0,
97 ),
98 )
99 }
100
101 #[inline]
103 pub const fn multiply(&self, rhs: &Self) -> Self {
104 let mut out = $mont_type([0; <$uint>::LIMBS]);
105 $mul(
106 &mut out,
107 &$mont_type(self.0.to_montgomery_words()),
108 &$mont_type(rhs.0.to_montgomery_words()),
109 );
110 Self(
111 $crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
112 out.0,
113 ),
114 )
115 }
116
117 #[inline]
119 pub const fn neg(&self) -> Self {
120 let mut out = $mont_type([0; <$uint>::LIMBS]);
121 $neg(&mut out, &$mont_type(self.0.to_montgomery_words()));
122 Self(
123 $crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
124 out.0,
125 ),
126 )
127 }
128
129 #[inline]
131 #[must_use]
132 pub const fn square(&self) -> Self {
133 let mut out = $mont_type([0; <$uint>::LIMBS]);
134 $square(&mut out, &$mont_type(self.0.to_montgomery_words()));
135 Self(
136 $crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
137 out.0,
138 ),
139 )
140 }
141
142 #[doc = stringify!($fe)]
144 #[inline]
146 pub fn invert(&self) -> $crate::subtle::CtOption<Self> {
147 $crate::subtle::CtOption::new(self.invert_unchecked(), !self.is_zero())
148 }
149
150 pub const fn const_invert(&self) -> Self {
154 assert!(
155 !self.0.as_montgomery().cmp_vartime(&<$uint>::ZERO).is_eq(),
156 "input to invert should be non-zero"
157 );
158 self.invert_unchecked()
159 }
160
161 const fn invert_unchecked(&self) -> Self {
165 let words = $crate::fiat_bernstein_yang_invert!(
166 a: &$mont_type(self.0.to_montgomery_words()),
167 one: &$mont_type(Self::ONE.0.to_montgomery_words()),
168 d: <$fe as $crate::ff::PrimeField>::NUM_BITS as usize,
169 nlimbs: <$uint>::LIMBS,
170 word: $crate::bigint::Word,
171 non_mont: $non_mont_type,
172 mont: $mont_type,
173 from_mont: $from_mont,
174 mul: $mul,
175 neg: $neg,
176 divstep_precomp: $divstep_precomp,
177 divstep: $divstep,
178 msat: $msat,
179 selectnz: $selectznz
180 );
181
182 Self(
183 $crate::MontyFieldElement::<$params, { <$uint>::LIMBS }>::from_montgomery_words(
184 words,
185 ),
186 )
187 }
188 }
189 };
190}
191
192#[macro_export]
195macro_rules! fiat_bernstein_yang_invert {
196 (
197 a: $a:expr,
198 one: $one:expr,
199 d: $d:expr,
200 nlimbs: $nlimbs:expr,
201 word: $word:ty,
202 non_mont: $non_mont_type: expr,
203 mont: $mont_type: expr,
204 from_mont: $from_mont:ident,
205 mul: $mul:ident,
206 neg: $neg:ident,
207 divstep_precomp: $divstep_precomp:ident,
208 divstep: $divstep:ident,
209 msat: $msat:ident,
210 selectnz: $selectznz:ident
211 ) => {{
212 const ITERATIONS: usize = (49 * $d + 57) / 17;
214
215 let mut a = $non_mont_type([0; $nlimbs]);
216 $from_mont(&mut a, $a);
217 let mut d = 1;
218 let mut f = [0; $nlimbs + 1];
219 $msat(&mut f);
220 let mut g = [0; $nlimbs + 1];
221 let mut v = [0; $nlimbs];
222 let mut r = $one.0;
223 let mut i = 0;
224 let mut j = 0;
225
226 while j < $nlimbs {
227 g[j] = a.0[j];
228 j += 1;
229 }
230
231 while i < ITERATIONS - ITERATIONS % 2 {
232 let mut out1 = 0;
233 let mut out2 = [0; $nlimbs + 1];
234 let mut out3 = [0; $nlimbs + 1];
235 let mut out4 = [0; $nlimbs];
236 let mut out5 = [0; $nlimbs];
237
238 $divstep(
239 &mut out1, &mut out2, &mut out3, &mut out4, &mut out5, d, &f, &g, &v, &r,
240 );
241 $divstep(
242 &mut d, &mut f, &mut g, &mut v, &mut r, out1, &out2, &out3, &out4, &out5,
243 );
244 i += 2;
245 }
246
247 if ITERATIONS % 2 != 0 {
248 let mut out1 = 0;
249 let mut out2 = [0; $nlimbs + 1];
250 let mut out3 = [0; $nlimbs + 1];
251 let mut out4 = [0; $nlimbs];
252 let mut out5 = [0; $nlimbs];
253 $divstep(
254 &mut out1, &mut out2, &mut out3, &mut out4, &mut out5, d, &f, &g, &v, &r,
255 );
256 f = out2;
257 v = out4;
258 }
259
260 let s = ((f[f.len() - 1] >> <$word>::BITS - 1) & 1) as u8;
261 let mut neg_v = $mont_type([0; $nlimbs]);
262 $neg(&mut neg_v, &$mont_type(v));
263
264 let mut v2 = $mont_type([0; $nlimbs]);
265 $selectznz(&mut v2.0, s, &v, &neg_v.0);
266
267 let mut precomp = $mont_type([0; $nlimbs]);
268 $divstep_precomp(&mut precomp.0);
269
270 let mut out = $mont_type([0; $nlimbs]);
271 $mul(&mut out, &v2, &precomp);
272 out.0
273 }};
274}
275
276#[macro_export]
285macro_rules! test_fiat_monty_field_arithmetic {
286 (
287 name: $fe:tt,
288 params: $params:ty,
289 uint: $uint:ty,
290 non_mont: $non_mont_type:expr,
291 mont: $mont_type:expr,
292 to_mont: $to_mont:ident,
293 msat: $msat:ident
294 ) => {
295 use $crate::bigint::modular::ConstMontyParams as _;
296
297 #[test]
301 fn fiat_montgomery_r_constant() {
302 let mut one = $non_mont_type([0; <$uint>::LIMBS]);
303 one[0] = 1;
304
305 let mut R = $mont_type([0; <$uint>::LIMBS]);
306 $to_mont(&mut R, &one);
307
308 assert_eq!(<$params>::PARAMS.one().as_words(), &R.0)
309 }
310
311 #[test]
315 fn fiat_msat_constant() {
316 use $crate::bigint::Word;
317
318 let mut out = [0 as Word; <$uint>::LIMBS + 1];
319 $msat(&mut out);
320 assert_eq!(out[<$uint>::LIMBS], 0);
321 assert_eq!(
322 <$params>::PARAMS.modulus().as_words(),
323 &out[..<$uint>::LIMBS]
324 );
325 }
326 };
327}