1#![recursion_limit = "1024"]
2#![allow(clippy::manual_repeat_n)]
3
4extern crate proc_macro;
5extern crate proc_macro2;
6
7use std::{iter, str::FromStr};
8
9use num_bigint::BigUint;
10use num_integer::Integer;
11use num_traits::{One, ToPrimitive, Zero};
12use quote::{quote, TokenStreamExt};
13
14mod pow_fixed;
15
16enum ReprEndianness {
17 Big,
18 Little,
19}
20
21impl FromStr for ReprEndianness {
22 type Err = ();
23
24 fn from_str(s: &str) -> Result<Self, Self::Err> {
25 match s {
26 "big" => Ok(ReprEndianness::Big),
27 "little" => Ok(ReprEndianness::Little),
28 _ => Err(()),
29 }
30 }
31}
32
33impl ReprEndianness {
34 fn modulus_repr(&self, modulus: &BigUint, bytes: usize) -> Vec<u8> {
35 match self {
36 ReprEndianness::Big => {
37 let buf = modulus.to_bytes_be();
38 iter::repeat(0).take(bytes - buf.len()).chain(buf).collect()
39 }
40 ReprEndianness::Little => {
41 let mut buf = modulus.to_bytes_le();
42 buf.extend(iter::repeat(0).take(bytes - buf.len()));
43 buf
44 }
45 }
46 }
47
48 #[allow(clippy::wrong_self_convention)]
50 fn from_repr(&self, name: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream {
51 let read_repr = match self {
52 ReprEndianness::Big => quote! {
53 <#name as ::openvm_algebra_guest::IntMod>::from_be_bytes(&r.as_ref()).unwrap()
54 },
55 ReprEndianness::Little => quote! {
56 <#name as ::openvm_algebra_guest::IntMod>::from_le_bytes(&r.as_ref()).unwrap()
57 },
58 };
59
60 let zkvm_impl = quote! {
61 #read_repr
62 };
63
64 let read_repr = match self {
65 ReprEndianness::Big => quote! {
66 ::ff::derive::byteorder::BigEndian::read_u64_into(r.as_ref(), &mut inner[..]);
67 inner.reverse();
68 },
69 ReprEndianness::Little => quote! {
70 ::ff::derive::byteorder::LittleEndian::read_u64_into(r.as_ref(), &mut inner[..]);
71 },
72 };
73
74 let non_zkvm_impl = quote! {
75 {
76 use ::ff::derive::byteorder::ByteOrder;
77
78 let mut inner = [0u64; #limbs];
79 #read_repr
80 #name(inner)
81 }
82 };
83
84 quote! {
85 #[cfg(target_os = "zkvm")]
86 let r = #zkvm_impl;
87 #[cfg(not(target_os = "zkvm"))]
88 let r = #non_zkvm_impl;
89 }
90 }
91
92 fn to_repr(
93 &self,
94 repr: proc_macro2::TokenStream,
95 mont_reduce_self_params: &proc_macro2::TokenStream,
96 limbs: usize,
97 ) -> proc_macro2::TokenStream {
98 let bytes = limbs * 8;
99
100 let write_repr = match self {
101 ReprEndianness::Big => quote! {
102 <Self as ::openvm_algebra_guest::IntMod>::to_be_bytes(self)[..#bytes].try_into().unwrap()
103 },
104 ReprEndianness::Little => quote! {
105 <Self as ::openvm_algebra_guest::IntMod>::as_le_bytes(self)[..#bytes].try_into().unwrap()
106 },
107 };
108
109 let zkvm_impl = quote! {
110 #repr(#write_repr)
111 };
112
113 let write_repr = match self {
114 ReprEndianness::Big => quote! {
115 r.0.reverse();
116 ::ff::derive::byteorder::BigEndian::write_u64_into(&r.0, &mut repr[..]);
117 },
118 ReprEndianness::Little => quote! {
119 ::ff::derive::byteorder::LittleEndian::write_u64_into(&r.0, &mut repr[..]);
120 },
121 };
122
123 let non_zkvm_impl = quote! {
124 use ::ff::derive::byteorder::ByteOrder;
125
126 let mut r = *self;
127 r.mont_reduce(
128 #mont_reduce_self_params
129 );
130
131 let mut repr = [0u8; #bytes];
132 #write_repr
133 #repr(repr)
134 };
135
136 quote! {
137 #[cfg(target_os = "zkvm")]
138 {
139 #zkvm_impl
140 }
141 #[cfg(not(target_os = "zkvm"))]
142 {
143 #non_zkvm_impl
144 }
145 }
146 }
147
148 fn iter_be(&self) -> proc_macro2::TokenStream {
149 match self {
152 ReprEndianness::Big => quote! {self.0.iter()},
153 ReprEndianness::Little => quote! {self.0.iter().rev()},
154 }
155 }
156}
157
158#[proc_macro_attribute]
168pub fn openvm_prime_field(
169 _: proc_macro::TokenStream,
170 input: proc_macro::TokenStream,
171) -> proc_macro::TokenStream {
172 let ast: syn::Item = syn::parse_macro_input!(input);
174
175 let mut ast = match ast {
177 syn::Item::Struct(ast) => ast,
178 _ => {
179 return syn::Error::new_spanned(ast, "PrimeField derive only works for structs.")
180 .to_compile_error()
181 .into();
182 }
183 };
184
185 let modulus: BigUint = fetch_attr("PrimeFieldModulus", &ast.attrs)
187 .expect("Please supply a PrimeFieldModulus attribute")
188 .parse()
189 .expect("PrimeFieldModulus should be a number");
190
191 let generator: BigUint = fetch_attr("PrimeFieldGenerator", &ast.attrs)
195 .expect("Please supply a PrimeFieldGenerator attribute")
196 .parse()
197 .expect("PrimeFieldGenerator should be a number");
198
199 let endianness = fetch_attr("PrimeFieldReprEndianness", &ast.attrs)
201 .expect("Please supply a PrimeFieldReprEndianness attribute")
202 .parse()
203 .expect("PrimeFieldReprEndianness should be 'big' or 'little'");
204
205 let mut limbs = 1;
208 {
209 let mod2 = (&modulus) << 1; let mut cur = BigUint::one() << 64; while cur < mod2 {
212 limbs += 1;
213 cur <<= 64;
214 }
215 }
216
217 let bytes = modulus.bits().div_ceil(8);
218 let zkvm_limbs = if bytes <= 32 {
219 32
220 } else if bytes <= 48 {
221 48
222 } else {
223 return syn::Error::new_spanned(
225 ast,
226 "PrimeField modulus is too large. Only 48 byte moduli are supported.",
227 )
228 .to_compile_error()
229 .into();
230 };
231
232 if let Some(err) = validate_struct(&ast, limbs) {
234 return err.into();
235 }
236
237 let repr_ident = syn::Ident::new(
239 &format!("{}Repr", ast.ident),
240 proc_macro2::Span::call_site(),
241 );
242
243 let mut gen = proc_macro2::TokenStream::new();
244
245 ast.attrs.clear();
247
248 let openvm_struct = openvm_struct_impl(&ast, &modulus);
250
251 gen.extend(quote! {
253 #[cfg(target_os = "zkvm")]
254 #openvm_struct
255 #[cfg(not(target_os = "zkvm"))]
256 #ast
257 });
258
259 let (constants_impl, sqrt_impl) =
260 prime_field_constants_and_sqrt(&ast.ident, &modulus, limbs, zkvm_limbs, generator);
261
262 gen.extend(constants_impl);
263 gen.extend(prime_field_repr_impl(&repr_ident, &endianness, limbs * 8));
264 gen.extend(prime_field_impl(
265 &ast.ident,
266 &repr_ident,
267 &modulus,
268 &endianness,
269 limbs,
270 zkvm_limbs,
271 sqrt_impl,
272 ));
273
274 gen.into()
276}
277
278fn openvm_struct_impl(ast: &syn::ItemStruct, modulus: &BigUint) -> proc_macro2::TokenStream {
279 let struct_ident = &ast.ident;
280 let modulus_str = modulus.to_str_radix(10);
281 quote! {
282 ::openvm_algebra_moduli_macros::moduli_declare! {
283 #struct_ident {
284 modulus = #modulus_str
285 }
286 }
287 }
288}
289
290fn validate_struct(ast: &syn::ItemStruct, limbs: usize) -> Option<proc_macro2::TokenStream> {
292 let fields = match &ast.fields {
294 syn::Fields::Unnamed(x) if x.unnamed.len() == 1 => x,
295 _ => {
296 return Some(
297 syn::Error::new_spanned(
298 &ast.ident,
299 format!(
300 "The struct must contain an array of limbs. Change this to `{}([u64; {}])`",
301 ast.ident, limbs,
302 ),
303 )
304 .to_compile_error(),
305 )
306 }
307 };
308 let field = &fields.unnamed[0];
309
310 let arr = match &field.ty {
312 syn::Type::Array(x) => x,
313 _ => {
314 return Some(
315 syn::Error::new_spanned(
316 field,
317 format!(
318 "The inner field must be an array of limbs. Change this to `[u64; {}]`",
319 limbs,
320 ),
321 )
322 .to_compile_error(),
323 )
324 }
325 };
326
327 if match arr.elem.as_ref() {
329 syn::Type::Path(path) => path.path.get_ident().map(|x| *x != "u64").unwrap_or(true),
330 _ => true,
331 } {
332 return Some(
333 syn::Error::new_spanned(
334 arr,
335 format!(
336 "PrimeField derive requires 64-bit limbs. Change this to `[u64; {}]",
337 limbs
338 ),
339 )
340 .to_compile_error(),
341 );
342 }
343
344 let expr_lit = match &arr.len {
346 syn::Expr::Lit(expr_lit) => Some(&expr_lit.lit),
347 syn::Expr::Group(expr_group) => match &*expr_group.expr {
348 syn::Expr::Lit(expr_lit) => Some(&expr_lit.lit),
349 _ => None,
350 },
351 _ => None,
352 };
353 let lit_int = match match expr_lit {
354 Some(syn::Lit::Int(lit_int)) => Some(lit_int),
355 _ => None,
356 } {
357 Some(x) => x,
358 _ => {
359 return Some(
360 syn::Error::new_spanned(
361 arr,
362 format!("To derive PrimeField, change this to `[u64; {}]`.", limbs),
363 )
364 .to_compile_error(),
365 )
366 }
367 };
368 if lit_int.base10_digits() != limbs.to_string() {
369 return Some(
370 syn::Error::new_spanned(
371 lit_int,
372 format!("The given modulus requires {} limbs.", limbs),
373 )
374 .to_compile_error(),
375 );
376 }
377
378 match &field.vis {
380 syn::Visibility::Inherited => (),
381 _ => {
382 return Some(
383 syn::Error::new_spanned(&field.vis, "Field must not be public.").to_compile_error(),
384 )
385 }
386 }
387
388 None
390}
391
392fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option<String> {
394 for attr in attrs {
395 if let Ok(meta) = attr.parse_meta() {
396 match meta {
397 syn::Meta::NameValue(nv) => {
398 if nv.path.get_ident().map(|i| i.to_string()) == Some(name.to_string()) {
399 match nv.lit {
400 syn::Lit::Str(ref s) => return Some(s.value()),
401 _ => {
402 panic!("attribute {} should be a string", name);
403 }
404 }
405 }
406 }
407 _ => {
408 panic!("attribute {} should be a string", name);
409 }
410 }
411 }
412 }
413
414 None
415}
416
417fn prime_field_repr_impl(
419 repr: &syn::Ident,
420 endianness: &ReprEndianness,
421 bytes: usize,
422) -> proc_macro2::TokenStream {
423 let repr_iter_be = endianness.iter_be();
424
425 quote! {
426 #[derive(Copy, Clone)]
427 pub struct #repr(pub [u8; #bytes]);
428
429 impl ::ff::derive::subtle::ConstantTimeEq for #repr {
430 fn ct_eq(&self, other: &#repr) -> ::ff::derive::subtle::Choice {
431 self.0
432 .iter()
433 .zip(other.0.iter())
434 .map(|(a, b)| a.ct_eq(b))
435 .fold(1.into(), |acc, x| acc & x)
436 }
437 }
438
439 impl ::core::cmp::PartialEq for #repr {
440 fn eq(&self, other: &#repr) -> bool {
441 use ::ff::derive::subtle::ConstantTimeEq;
442 self.ct_eq(other).into()
443 }
444 }
445
446 impl ::core::cmp::Eq for #repr { }
447
448 impl ::core::default::Default for #repr {
449 fn default() -> #repr {
450 #repr([0u8; #bytes])
451 }
452 }
453
454 impl ::core::fmt::Debug for #repr
455 {
456 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
457 write!(f, "0x")?;
458 for i in #repr_iter_be {
459 write!(f, "{:02x}", *i)?;
460 }
461
462 Ok(())
463 }
464 }
465
466 impl AsRef<[u8]> for #repr {
467 #[inline(always)]
468 fn as_ref(&self) -> &[u8] {
469 &self.0
470 }
471 }
472
473 impl AsMut<[u8]> for #repr {
474 #[inline(always)]
475 fn as_mut(&mut self) -> &mut [u8] {
476 &mut self.0
477 }
478 }
479 }
480}
481
482fn biguint_to_real_u64_vec(mut v: BigUint, limbs: usize) -> Vec<u64> {
484 let m = BigUint::one() << 64;
485 let mut ret = vec![];
486
487 while v > BigUint::zero() {
488 let limb: BigUint = &v % &m;
489 ret.push(limb.to_u64().unwrap());
490 v >>= 64;
491 }
492
493 while ret.len() < limbs {
494 ret.push(0);
495 }
496
497 assert!(ret.len() == limbs);
498
499 ret
500}
501
502fn biguint_to_u64_vec(v: BigUint, limbs: usize) -> proc_macro2::TokenStream {
504 let ret = biguint_to_real_u64_vec(v, limbs);
505 quote!([#(#ret,)*])
506}
507
508fn biguint_to_u8_vec(v: BigUint, limbs: usize) -> proc_macro2::TokenStream {
510 let mut bytes = v.to_bytes_le();
511 while bytes.len() < limbs {
512 bytes.push(0);
513 }
514 quote!([#(#bytes,)*])
515}
516
517fn biguint_num_bits(mut v: BigUint) -> u32 {
518 let mut bits = 0;
519
520 while v != BigUint::zero() {
521 v >>= 1;
522 bits += 1;
523 }
524
525 bits
526}
527
528fn exp(base: BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
530 let mut ret = BigUint::one();
531
532 for i in exp
533 .to_bytes_be()
534 .into_iter()
535 .flat_map(|x| (0..8).rev().map(move |i| (x >> i).is_odd()))
536 {
537 ret = (&ret * &ret) % modulus;
538 if i {
539 ret = (ret * &base) % modulus;
540 }
541 }
542
543 ret
544}
545
546#[test]
547fn test_exp() {
548 assert_eq!(
549 exp(
550 BigUint::from_str("4398572349857239485729348572983472345").unwrap(),
551 &BigUint::from_str("5489673498567349856734895").unwrap(),
552 &BigUint::from_str(
553 "52435875175126190479447740508185965837690552500527637822603658699938581184513"
554 )
555 .unwrap()
556 ),
557 BigUint::from_str(
558 "4371221214068404307866768905142520595925044802278091865033317963560480051536"
559 )
560 .unwrap()
561 );
562}
563
564fn prime_field_constants_and_sqrt(
565 name: &syn::Ident,
566 modulus: &BigUint,
567 limbs: usize,
568 zkvm_limbs: usize,
569 generator: BigUint,
570) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
571 let bytes = limbs * 8;
572 let modulus_num_bits = biguint_num_bits(modulus.clone());
573
574 let repr_shave_bits = (64 * limbs as u32) - biguint_num_bits(modulus.clone());
579
580 let r = (BigUint::one() << (limbs * 64)) % modulus;
582 let to_mont = |v| (v * &r) % modulus;
583
584 let two = BigUint::from_str("2").unwrap();
585 let p_minus_2 = modulus - &two;
586 let invert = |v| exp(v, &p_minus_2, modulus);
587
588 let two_inv = biguint_to_u64_vec(to_mont(invert(two.clone())), limbs);
590 let two_inv_bytes = biguint_to_u8_vec(invert(two), zkvm_limbs);
591
592 let mut s: u32 = 0;
594 let mut t = modulus - BigUint::from_str("1").unwrap();
595 while t.is_even() {
596 t >>= 1;
597 s += 1;
598 }
599
600 let root_of_unity_biguint = exp(generator.clone(), &t, modulus);
602
603 let root_of_unity_inv_biguint = invert(root_of_unity_biguint.clone());
604 let root_of_unity_inv = biguint_to_u64_vec(to_mont(root_of_unity_inv_biguint.clone()), limbs);
605 let root_of_unity_inv_bytes = biguint_to_u8_vec(root_of_unity_inv_biguint, zkvm_limbs);
606
607 let root_of_unity = biguint_to_u64_vec(to_mont(root_of_unity_biguint.clone()), limbs);
608 let root_of_unity_bytes = biguint_to_u8_vec(root_of_unity_biguint, zkvm_limbs);
609
610 let delta_biguint = exp(generator.clone(), &(BigUint::one() << s), modulus);
611 let delta = biguint_to_u64_vec(to_mont(delta_biguint.clone()), limbs);
612 let delta_bytes = biguint_to_u8_vec(delta_biguint, zkvm_limbs);
613
614 let generator_u64_limbs = biguint_to_u64_vec(to_mont(generator.clone()), limbs);
615 let generator_bytes = biguint_to_u8_vec(generator, zkvm_limbs);
616
617 let sqrt_impl =
618 if (modulus % BigUint::from_str("4").unwrap()) == BigUint::from_str("3").unwrap() {
619 let mod_plus_1_over_4 = pow_fixed::generate(
621 "e! {self},
622 (modulus + BigUint::from_str("1").unwrap()) >> 2,
623 );
624
625 quote! {
626 use ::ff::derive::subtle::ConstantTimeEq;
627
628 let sqrt = {
632 #mod_plus_1_over_4
633 };
634
635 ::ff::derive::subtle::CtOption::new(
636 sqrt,
637 (sqrt * &sqrt).ct_eq(self), )
639 }
640 } else {
641 let t_minus_1_over_2 = if t == BigUint::one() {
643 quote!( #name::ONE )
644 } else {
645 pow_fixed::generate("e! {self}, (&t - BigUint::one()) >> 1)
646 };
647
648 quote! {
649 use ::ff::derive::subtle::{ConditionallySelectable, ConstantTimeEq};
652
653 let w = {
655 #t_minus_1_over_2
656 };
657
658 let mut v = S;
659 let mut x = *self * &w;
660 let mut b = x * &w;
661
662 let mut z = ROOT_OF_UNITY;
664
665 for max_v in (1..=S).rev() {
666 let mut k = 1;
667 let mut tmp = b.square();
668 let mut j_less_than_v: ::ff::derive::subtle::Choice = 1.into();
669
670 for j in 2..max_v {
671 let tmp_is_one = tmp.ct_eq(&#name::ONE);
672 let squared = #name::conditional_select(&tmp, &z, tmp_is_one).square();
673 tmp = #name::conditional_select(&squared, &tmp, tmp_is_one);
674 let new_z = #name::conditional_select(&z, &squared, tmp_is_one);
675 j_less_than_v &= !j.ct_eq(&v);
676 k = u32::conditional_select(&j, &k, tmp_is_one);
677 z = #name::conditional_select(&z, &new_z, j_less_than_v);
678 }
679
680 let result = x * &z;
681 x = #name::conditional_select(&result, &x, b.ct_eq(&#name::ONE));
682 z = z.square();
683 b *= &z;
684 v = k;
685 }
686
687 ::ff::derive::subtle::CtOption::new(
688 x,
689 (x * &x).ct_eq(self), )
691 }
692 };
693
694 let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs);
696
697 let r = biguint_to_u64_vec(r, limbs);
698 let modulus_le_bytes = ReprEndianness::Little.modulus_repr(modulus, limbs * 8);
699 let modulus_str = format!("0x{}", modulus.to_str_radix(16));
700 let modulus = biguint_to_real_u64_vec(modulus.clone(), limbs);
701
702 let mut inv = 1u64;
704 for _ in 0..63 {
705 inv = inv.wrapping_mul(inv);
706 inv = inv.wrapping_mul(modulus[0]);
707 }
708 inv = inv.wrapping_neg();
709
710 (
711 quote! {
712 type REPR_BYTES = [u8; #bytes];
713 type REPR_BITS = REPR_BYTES;
714
715 const MODULUS: REPR_BITS = [#(#modulus_le_bytes,)*];
717
718 #[cfg(not(target_os = "zkvm"))]
720 const MODULUS_LIMBS: #name = #name([#(#modulus,)*]);
721
722 const MODULUS_STR: &'static str = #modulus_str;
724
725 const MODULUS_BITS: u32 = #modulus_num_bits;
727
728 const REPR_SHAVE_BITS: u32 = #repr_shave_bits;
731
732 #[cfg(not(target_os = "zkvm"))]
734 const R: #name = #name(#r);
735
736 #[cfg(not(target_os = "zkvm"))]
738 const R2: #name = #name(#r2);
739
740 #[cfg(not(target_os = "zkvm"))]
742 const INV: u64 = #inv;
743
744 #[cfg(target_os = "zkvm")]
746 const TWO_INV: #name = <#name>::from_const_bytes(#two_inv_bytes);
747 #[cfg(not(target_os = "zkvm"))]
748 const TWO_INV: #name = #name(#two_inv);
749
750 #[cfg(target_os = "zkvm")]
753 const GENERATOR: #name = <#name>::from_const_bytes(#generator_bytes);
754 #[cfg(not(target_os = "zkvm"))]
755 const GENERATOR: #name = #name(#generator_u64_limbs);
756
757 const S: u32 = #s;
759
760 #[cfg(target_os = "zkvm")]
762 const ROOT_OF_UNITY: #name = <#name>::from_const_bytes(#root_of_unity_bytes);
763 #[cfg(not(target_os = "zkvm"))]
764 const ROOT_OF_UNITY: #name = #name(#root_of_unity);
765
766 #[cfg(target_os = "zkvm")]
768 const ROOT_OF_UNITY_INV: #name = <#name>::from_const_bytes(#root_of_unity_inv_bytes);
769 #[cfg(not(target_os = "zkvm"))]
770 const ROOT_OF_UNITY_INV: #name = #name(#root_of_unity_inv);
771
772 #[cfg(target_os = "zkvm")]
774 const DELTA: #name = <#name>::from_const_bytes(#delta_bytes);
775 #[cfg(not(target_os = "zkvm"))]
776 const DELTA: #name = #name(#delta);
777 },
778 sqrt_impl,
779 )
780}
781
782fn prime_field_impl(
784 name: &syn::Ident,
785 repr: &syn::Ident,
786 modulus: &BigUint,
787 endianness: &ReprEndianness,
788 limbs: usize,
789 zkvm_limbs: usize,
790 sqrt_impl: proc_macro2::TokenStream,
791) -> proc_macro2::TokenStream {
792 fn get_temp(n: usize) -> syn::Ident {
794 syn::Ident::new(&format!("r{}", n), proc_macro2::Span::call_site())
795 }
796
797 let mut mont_paramlist = proc_macro2::TokenStream::new();
800 mont_paramlist.append_separated(
801 (0..(limbs * 2)).map(|i| (i, get_temp(i))).map(|(i, x)| {
802 if i != 0 {
803 quote! {mut #x: u64}
804 } else {
805 quote! {#x: u64}
806 }
807 }),
808 proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
809 );
810
811 fn mont_impl(limbs: usize) -> proc_macro2::TokenStream {
813 #[cfg(target_os = "zkvm")]
814 {
815 quote! {
816 unimplemented!();
817 }
818 }
819 #[cfg(not(target_os = "zkvm"))]
820 {
821 let mut gen = proc_macro2::TokenStream::new();
822
823 for i in 0..limbs {
824 {
825 let temp = get_temp(i);
826 gen.extend(quote! {
827 let k = #temp.wrapping_mul(INV);
828 let (_, carry) = ::ff::derive::mac(#temp, k, MODULUS_LIMBS.0[0], 0);
829 });
830 }
831
832 for j in 1..limbs {
833 let temp = get_temp(i + j);
834 gen.extend(quote! {
835 let (#temp, carry) = ::ff::derive::mac(#temp, k, MODULUS_LIMBS.0[#j], carry);
836 });
837 }
838
839 let temp = get_temp(i + limbs);
840
841 if i == 0 {
842 gen.extend(quote! {
843 let (#temp, carry2) = ::ff::derive::adc(#temp, 0, carry);
844 });
845 } else {
846 gen.extend(quote! {
847 let (#temp, carry2) = ::ff::derive::adc(#temp, carry2, carry);
848 });
849 }
850 }
851
852 for i in 0..limbs {
853 let temp = get_temp(limbs + i);
854
855 gen.extend(quote! {
856 self.0[#i] = #temp;
857 });
858 }
859
860 gen
861 }
862 }
863
864 fn sqr_impl(a: proc_macro2::TokenStream, limbs: usize) -> proc_macro2::TokenStream {
865 let mut gen = proc_macro2::TokenStream::new();
866
867 if limbs > 1 {
868 for i in 0..(limbs - 1) {
869 gen.extend(quote! {
870 let carry = 0;
871 });
872
873 for j in (i + 1)..limbs {
874 let temp = get_temp(i + j);
875 if i == 0 {
876 gen.extend(quote! {
877 let (#temp, carry) = ::ff::derive::mac(0, #a.0[#i], #a.0[#j], carry);
878 });
879 } else {
880 gen.extend(quote! {
881 let (#temp, carry) = ::ff::derive::mac(#temp, #a.0[#i], #a.0[#j], carry);
882 });
883 }
884 }
885
886 let temp = get_temp(i + limbs);
887
888 gen.extend(quote! {
889 let #temp = carry;
890 });
891 }
892
893 for i in 1..(limbs * 2) {
894 let temp0 = get_temp(limbs * 2 - i);
895 let temp1 = get_temp(limbs * 2 - i - 1);
896
897 if i == 1 {
898 gen.extend(quote! {
899 let #temp0 = #temp1 >> 63;
900 });
901 } else if i == (limbs * 2 - 1) {
902 gen.extend(quote! {
903 let #temp0 = #temp0 << 1;
904 });
905 } else {
906 gen.extend(quote! {
907 let #temp0 = (#temp0 << 1) | (#temp1 >> 63);
908 });
909 }
910 }
911 } else {
912 let temp1 = get_temp(1);
913 gen.extend(quote! {
914 let #temp1 = 0;
915 });
916 }
917
918 for i in 0..limbs {
919 let temp0 = get_temp(i * 2);
920 let temp1 = get_temp(i * 2 + 1);
921 if i == 0 {
922 gen.extend(quote! {
923 let (#temp0, carry) = ::ff::derive::mac(0, #a.0[#i], #a.0[#i], 0);
924 });
925 } else {
926 gen.extend(quote! {
927 let (#temp0, carry) = ::ff::derive::mac(#temp0, #a.0[#i], #a.0[#i], carry);
928 });
929 }
930
931 gen.extend(quote! {
932 let (#temp1, carry) = ::ff::derive::adc(#temp1, 0, carry);
933 });
934 }
935
936 let mut mont_calling = proc_macro2::TokenStream::new();
937 mont_calling.append_separated(
938 (0..(limbs * 2)).map(get_temp),
939 proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
940 );
941
942 gen.extend(quote! {
943 let mut ret = *self;
944 ret.mont_reduce(#mont_calling);
945 ret
946 });
947
948 gen
949 }
950
951 fn mul_impl(
952 a: proc_macro2::TokenStream,
953 b: proc_macro2::TokenStream,
954 limbs: usize,
955 ) -> proc_macro2::TokenStream {
956 let mut gen = proc_macro2::TokenStream::new();
957
958 for i in 0..limbs {
959 gen.extend(quote! {
960 let carry = 0;
961 });
962
963 for j in 0..limbs {
964 let temp = get_temp(i + j);
965
966 if i == 0 {
967 gen.extend(quote! {
968 let (#temp, carry) = ::ff::derive::mac(0, #a.0[#i], #b.0[#j], carry);
969 });
970 } else {
971 gen.extend(quote! {
972 let (#temp, carry) = ::ff::derive::mac(#temp, #a.0[#i], #b.0[#j], carry);
973 });
974 }
975 }
976
977 let temp = get_temp(i + limbs);
978
979 gen.extend(quote! {
980 let #temp = carry;
981 });
982 }
983
984 let mut mont_calling = proc_macro2::TokenStream::new();
985 mont_calling.append_separated(
986 (0..(limbs * 2)).map(get_temp),
987 proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
988 );
989
990 gen.extend(quote! {
991 self.mont_reduce(#mont_calling);
992 });
993
994 gen
995 }
996
997 fn inv_impl(a: proc_macro2::TokenStream, modulus: &BigUint) -> proc_macro2::TokenStream {
1000 let mod_minus_2 = pow_fixed::generate(&a, modulus - BigUint::from(2u64));
1002
1003 quote! {
1004 use ::ff::derive::subtle::ConstantTimeEq;
1005
1006 let inv = {
1013 #mod_minus_2
1014 };
1015
1016 ::ff::derive::subtle::CtOption::new(inv, !#a.is_zero())
1017 }
1018 }
1019
1020 let squaring_impl = sqr_impl(quote! {self}, limbs);
1021 let multiply_impl = mul_impl(quote! {self}, quote! {other}, limbs);
1022 let invert_impl = inv_impl(quote! {self}, modulus);
1023 let montgomery_impl = mont_impl(limbs);
1024
1025 fn mont_reduce_params(a: proc_macro2::TokenStream, limbs: usize) -> proc_macro2::TokenStream {
1026 let mut mont_reduce_params = proc_macro2::TokenStream::new();
1028 mont_reduce_params.append_separated(
1029 (0..limbs)
1030 .map(|i| quote! { #a.0[#i] })
1031 .chain((0..limbs).map(|_| quote! {0})),
1032 proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
1033 );
1034 mont_reduce_params
1035 }
1036
1037 let mont_reduce_self_params = mont_reduce_params(quote! {self}, limbs);
1038 let mont_reduce_other_params = mont_reduce_params(quote! {other}, limbs);
1039
1040 let from_repr_impl = endianness.from_repr(name, limbs);
1041 let to_repr_impl = endianness.to_repr(quote! {#repr}, &mont_reduce_self_params, limbs);
1042
1043 let prime_field_bits_impl = if cfg!(feature = "bits") {
1044 let to_le_bits_impl = ReprEndianness::Little.to_repr(
1045 quote! {::ff::derive::bitvec::array::BitArray::new},
1046 &mont_reduce_self_params,
1047 limbs,
1048 );
1049
1050 Some(quote! {
1051 impl ::ff::PrimeFieldBits for #name {
1052 type ReprBits = REPR_BITS;
1053
1054 fn to_le_bits(&self) -> ::ff::FieldBits<REPR_BITS> {
1055 #to_le_bits_impl
1056 }
1057
1058 fn char_le_bits() -> ::ff::FieldBits<REPR_BITS> {
1059 ::ff::FieldBits::new(MODULUS)
1060 }
1061 }
1062 })
1063 } else {
1064 None
1065 };
1066
1067 let top_limb_index = limbs - 1;
1068
1069 let impl_module_ident =
1073 syn::Ident::new(&format!("impl_{}", name), proc_macro2::Span::call_site());
1074
1075 let zero_impl = quote! {
1076 #[cfg(target_os = "zkvm")]
1077 const ZERO: Self = <Self as ::openvm_algebra_guest::IntMod>::ZERO;
1078 #[cfg(not(target_os = "zkvm"))]
1079 const ZERO: Self = #name([0; #limbs]);
1080 };
1081 let one_impl = quote! {
1082 #[cfg(target_os = "zkvm")]
1083 const ONE: Self = <Self as ::openvm_algebra_guest::IntMod>::ONE;
1084 #[cfg(not(target_os = "zkvm"))]
1085 const ONE: Self = R;
1086 };
1087
1088 quote! {
1089 impl ::core::marker::Copy for #name { }
1090
1091 impl ::core::default::Default for #name {
1092 fn default() -> #name {
1093 use ::ff::Field;
1094 #name::ZERO
1095 }
1096 }
1097
1098 impl ::ff::derive::subtle::ConstantTimeEq for #name {
1099 fn ct_eq(&self, other: &#name) -> ::ff::derive::subtle::Choice {
1100 use ::ff::PrimeField;
1101 self.to_repr().ct_eq(&other.to_repr())
1102 }
1103 }
1104
1105 impl Ord for #name {
1107 #[inline(always)]
1108 fn cmp(&self, other: &#name) -> ::core::cmp::Ordering {
1109 #[cfg(target_os = "zkvm")]
1110 {
1111 <Self as ::openvm_algebra_guest::IntMod>::assert_reduced(self);
1112 <Self as ::openvm_algebra_guest::IntMod>::assert_reduced(other);
1113
1114 self.cmp_native(other)
1115 }
1116 #[cfg(not(target_os = "zkvm"))]
1117 {
1118 let mut a = *self;
1119 a.mont_reduce(
1120 #mont_reduce_self_params
1121 );
1122
1123 let mut b = *other;
1124 b.mont_reduce(
1125 #mont_reduce_other_params
1126 );
1127
1128 a.cmp_native(&b)
1129 }
1130 }
1131 }
1132
1133 impl PartialOrd for #name {
1134 #[inline(always)]
1135 fn partial_cmp(&self, other: &#name) -> Option<::core::cmp::Ordering> {
1136 Some(self.cmp(other))
1137 }
1138 }
1139
1140 impl From<u64> for #name {
1141 #[inline(always)]
1142 fn from(val: u64) -> #name {
1143 #[cfg(target_os = "zkvm")]
1144 {
1145 <#name as ::openvm_algebra_guest::IntMod>::from_u64(val)
1146 }
1147 #[cfg(not(target_os = "zkvm"))]
1148 {
1149 let mut raw = [0u64; #limbs];
1150 raw[0] = val;
1151 #name(raw) * R2
1152 }
1153 }
1154 }
1155
1156 impl From<#name> for #repr {
1157 fn from(e: #name) -> #repr {
1158 use ::ff::PrimeField;
1159 e.to_repr()
1160 }
1161 }
1162
1163 impl<'a> From<&'a #name> for #repr {
1164 fn from(e: &'a #name) -> #repr {
1165 use ::ff::PrimeField;
1166 e.to_repr()
1167 }
1168 }
1169
1170 impl ::ff::derive::subtle::ConditionallySelectable for #name {
1171 fn conditional_select(a: &#name, b: &#name, choice: ::ff::derive::subtle::Choice) -> #name {
1172 #[cfg(target_os = "zkvm")]
1173 {
1174 let mut res = [0u8; #zkvm_limbs];
1175 let a_le_bytes = <Self as ::openvm_algebra_guest::IntMod>::as_le_bytes(a);
1176 let b_le_bytes = <Self as ::openvm_algebra_guest::IntMod>::as_le_bytes(b);
1177 for i in 0..#zkvm_limbs {
1178 res[i] = u8::conditional_select(&a_le_bytes[i], &b_le_bytes[i], choice);
1179 }
1180 #name(res)
1181 }
1182 #[cfg(not(target_os = "zkvm"))]
1183 {
1184 let mut res = [0u64; #limbs];
1185 for i in 0..#limbs {
1186 res[i] = u64::conditional_select(&a.0[i], &b.0[i], choice);
1187 }
1188 #name(res)
1189 }
1190 }
1191 }
1192
1193 #[cfg(not(target_os = "zkvm"))]
1196 mod #impl_module_ident {
1197 use super::{#name, MODULUS_LIMBS};
1198
1199 impl ::core::clone::Clone for #name {
1200 fn clone(&self) -> #name {
1201 *self
1202 }
1203 }
1204
1205 impl ::core::cmp::PartialEq for #name {
1206 fn eq(&self, other: &#name) -> bool {
1207 use ::ff::derive::subtle::ConstantTimeEq;
1208 self.ct_eq(other).into()
1209 }
1210 }
1211
1212 impl ::core::cmp::Eq for #name { }
1213
1214 impl ::core::fmt::Debug for #name
1215 {
1216 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
1217 use ::ff::PrimeField;
1218 write!(f, "{}({:?})", stringify!(#name), self.to_repr())
1219 }
1220 }
1221
1222
1223 impl ::core::ops::Neg for #name {
1224 type Output = #name;
1225
1226 #[inline]
1227 fn neg(self) -> #name {
1228 use ::ff::Field;
1229
1230 let mut ret = self;
1231 if !ret.is_zero_vartime() {
1232 let mut tmp = MODULUS_LIMBS;
1233 tmp.sub_noborrow(&ret);
1234 ret = tmp;
1235 }
1236 ret
1237 }
1238 }
1239
1240 impl<'r> ::core::ops::Add<&'r #name> for #name {
1241 type Output = #name;
1242
1243 #[inline]
1244 fn add(self, other: &#name) -> #name {
1245 use ::core::ops::AddAssign;
1246
1247 let mut ret = self;
1248 ret.add_assign(other);
1249 ret
1250 }
1251 }
1252
1253 impl ::core::ops::Add for #name {
1254 type Output = #name;
1255
1256 #[inline]
1257 fn add(self, other: #name) -> Self {
1258 self + &other
1259 }
1260 }
1261
1262 impl<'r> ::core::ops::AddAssign<&'r #name> for #name {
1263 #[inline]
1264 fn add_assign(&mut self, other: &#name) {
1265 self.add_nocarry(other);
1267
1268 self.reduce();
1270 }
1271 }
1272
1273 impl ::core::ops::AddAssign for #name {
1274 #[inline]
1275 fn add_assign(&mut self, other: #name) {
1276 self.add_assign(&other);
1277 }
1278 }
1279
1280 impl<'r> ::core::ops::Sub<&'r #name> for #name {
1281 type Output = #name;
1282
1283 #[inline]
1284 fn sub(self, other: &#name) -> Self {
1285 use ::core::ops::SubAssign;
1286
1287 let mut ret = self;
1288 ret.sub_assign(other);
1289 ret
1290 }
1291 }
1292
1293 impl ::core::ops::Sub for #name {
1294 type Output = #name;
1295
1296 #[inline]
1297 fn sub(self, other: #name) -> Self {
1298 self - &other
1299 }
1300 }
1301
1302 impl<'r> ::core::ops::SubAssign<&'r #name> for #name {
1303 #[inline]
1304 fn sub_assign(&mut self, other: &#name) {
1305 if other.cmp_native(self) == ::core::cmp::Ordering::Greater {
1307 self.add_nocarry(&MODULUS_LIMBS);
1308 }
1309
1310 self.sub_noborrow(other);
1311 }
1312 }
1313
1314 impl ::core::ops::SubAssign for #name {
1315 #[inline]
1316 fn sub_assign(&mut self, other: #name) {
1317 self.sub_assign(&other);
1318 }
1319 }
1320
1321 impl<'r> ::core::ops::Mul<&'r #name> for #name {
1322 type Output = #name;
1323
1324 #[inline]
1325 fn mul(self, other: &#name) -> Self {
1326 use ::core::ops::MulAssign;
1327
1328 let mut ret = self;
1329 ret.mul_assign(other);
1330 ret
1331 }
1332 }
1333
1334 impl ::core::ops::Mul for #name {
1335 type Output = #name;
1336
1337 #[inline]
1338 fn mul(self, other: #name) -> Self {
1339 self * &other
1340 }
1341 }
1342
1343 impl<'r> ::core::ops::MulAssign<&'r #name> for #name {
1344 #[inline]
1345 fn mul_assign(&mut self, other: &#name)
1346 {
1347 #multiply_impl
1348 }
1349 }
1350
1351 impl ::core::ops::MulAssign for #name {
1352 #[inline]
1353 fn mul_assign(&mut self, other: #name)
1354 {
1355 self.mul_assign(&other);
1356 }
1357 }
1358
1359 impl<T: ::core::borrow::Borrow<#name>> ::core::iter::Sum<T> for #name {
1360 fn sum<I: Iterator<Item = T>>(iter: I) -> Self {
1361 use ::ff::Field;
1362
1363 iter.fold(Self::ZERO, |acc, item| acc + item.borrow())
1364 }
1365 }
1366
1367 impl<T: ::core::borrow::Borrow<#name>> ::core::iter::Product<T> for #name {
1368 fn product<I: Iterator<Item = T>>(iter: I) -> Self {
1369 use ::ff::Field;
1370
1371 iter.fold(Self::ONE, |acc, item| acc * item.borrow())
1372 }
1373 }
1374 }
1375
1376 impl ::ff::PrimeField for #name {
1377 type Repr = #repr;
1378
1379 fn from_repr(r: #repr) -> ::ff::derive::subtle::CtOption<#name> {
1380 #from_repr_impl
1381
1382 #[cfg(target_os = "zkvm")]
1383 {
1384 ::ff::derive::subtle::CtOption::new(r, r.constant_time_is_reduced())
1385 }
1386 #[cfg(not(target_os = "zkvm"))]
1387 {
1388 let borrow = r.0.iter().zip(MODULUS_LIMBS.0.iter()).fold(0, |borrow, (a, b)| {
1390 ::ff::derive::sbb(*a, *b, borrow).1
1391 });
1392
1393 let is_some = ::ff::derive::subtle::Choice::from((borrow as u8) & 1);
1397
1398 ::ff::derive::subtle::CtOption::new(r * &R2, is_some)
1401 }
1402 }
1403
1404 fn from_repr_vartime(r: #repr) -> Option<#name> {
1405 #from_repr_impl
1406
1407 #[cfg(target_os = "zkvm")]
1408 {
1409 if <Self as ::openvm_algebra_guest::IntMod>::is_reduced(&r) {
1410 Some(r)
1411 } else {
1412 None
1413 }
1414 }
1415 #[cfg(not(target_os = "zkvm"))]
1416 {
1417 if r.is_valid() {
1418 Some(r * R2)
1419 } else {
1420 None
1421 }
1422
1423 }
1424 }
1425
1426 fn to_repr(&self) -> #repr {
1427 #to_repr_impl
1428 }
1429
1430 #[inline(always)]
1431 fn is_odd(&self) -> ::ff::derive::subtle::Choice {
1432 #[cfg(target_os = "zkvm")]
1433 {
1434 ::ff::derive::subtle::Choice::from((<Self as ::openvm_algebra_guest::IntMod>::as_le_bytes(self)[0] & 1) as u8)
1435 }
1436 #[cfg(not(target_os = "zkvm"))]
1437 {
1438 let mut r = *self;
1439 r.mont_reduce(
1440 #mont_reduce_self_params
1441 );
1442
1443 ::ff::derive::subtle::Choice::from((r.0[0] & 1) as u8)
1446 }
1447 }
1448
1449 const MODULUS: &'static str = MODULUS_STR;
1450
1451 const NUM_BITS: u32 = MODULUS_BITS;
1452
1453 const CAPACITY: u32 = Self::NUM_BITS - 1;
1454
1455 const TWO_INV: Self = TWO_INV;
1456
1457 const MULTIPLICATIVE_GENERATOR: Self = GENERATOR;
1458
1459 const S: u32 = S;
1460
1461 const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
1462
1463 const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
1464
1465 const DELTA: Self = DELTA;
1466 }
1467
1468 #prime_field_bits_impl
1469
1470 impl ::ff::Field for #name {
1471 #zero_impl
1472 #one_impl
1473
1474 fn random(mut rng: impl ::ff::derive::rand_core::RngCore) -> Self {
1476 #[cfg(target_os = "zkvm")]
1477 {
1478 panic!("randomn is not implemented for the zkvm");
1479 }
1480 #[cfg(not(target_os = "zkvm"))]
1481 {
1482 loop {
1483 let mut tmp = {
1484 let mut repr = [0u64; #limbs];
1485 for i in 0..#limbs {
1486 repr[i] = rng.next_u64();
1487 }
1488 #name(repr)
1489 };
1490
1491 tmp.0[#top_limb_index] &= 0xffffffffffffffffu64.checked_shr(REPR_SHAVE_BITS).unwrap_or(0);
1497
1498 if tmp.is_valid() {
1499 return tmp
1500 }
1501 }
1502 }
1503 }
1504
1505 #[inline]
1506 fn is_zero_vartime(&self) -> bool {
1507 #[cfg(target_os = "zkvm")]
1508 {
1509 self == &Self::ZERO
1510 }
1511 #[cfg(not(target_os = "zkvm"))]
1512 {
1513 self.0.iter().all(|&e| e == 0)
1514 }
1515 }
1516
1517 #[inline]
1518 fn double(&self) -> Self {
1519 #[cfg(target_os = "zkvm")]
1520 {
1521 <Self as ::openvm_algebra_guest::IntMod>::double(self)
1522 }
1523 #[cfg(not(target_os = "zkvm"))]
1524 {
1525 let mut ret = *self;
1526
1527 let mut last = 0;
1529 for i in &mut ret.0 {
1530 let tmp = *i >> 63;
1531 *i <<= 1;
1532 *i |= last;
1533 last = tmp;
1534 }
1535
1536 ret.reduce();
1538
1539 ret
1540 }
1541 }
1542
1543 fn invert(&self) -> ::ff::derive::subtle::CtOption<Self> {
1545 #[cfg(target_os = "zkvm")]
1546 {
1547 let is_self_zero = self.is_zero_vartime();
1548 let res = if is_self_zero {
1549 <Self as ::openvm_algebra_guest::IntMod>::ZERO
1550 } else {
1551 use ::openvm_algebra_guest::DivUnsafe;
1552 <Self as ::openvm_algebra_guest::IntMod>::ONE.div_unsafe(self)
1553 };
1554 ::ff::derive::subtle::CtOption::new(res, (!is_self_zero as u8).into())
1555 }
1556 #[cfg(not(target_os = "zkvm"))]
1557 {
1558 #invert_impl
1559 }
1560 }
1561
1562 #[inline]
1563 fn square(&self) -> Self
1564 {
1565 #[cfg(target_os = "zkvm")]
1566 {
1567 <Self as ::openvm_algebra_guest::IntMod>::square(self)
1568 }
1569 #[cfg(not(target_os = "zkvm"))]
1570 {
1571 #squaring_impl
1572 }
1573 }
1574
1575 fn sqrt_ratio(num: &Self, div: &Self) -> (::ff::derive::subtle::Choice, Self) {
1576 ::ff::helpers::sqrt_ratio_generic(num, div)
1577 }
1578
1579 fn sqrt(&self) -> ::ff::derive::subtle::CtOption<Self> {
1581 #[cfg(target_os = "zkvm")]
1582 {
1583 use ::openvm_algebra_guest::Sqrt;
1584 match Sqrt::sqrt(self) {
1585 Some(sqrt) => ::ff::derive::subtle::CtOption::new(sqrt, 1u8.into()),
1586 None => ::ff::derive::subtle::CtOption::new(Self::ZERO, 0u8.into()),
1587 }
1588 }
1589 #[cfg(not(target_os = "zkvm"))]
1590 {
1591 #sqrt_impl
1592 }
1593 }
1594 }
1595
1596 impl #name {
1597 #[inline(always)]
1600 fn cmp_native(&self, other: &#name) -> ::core::cmp::Ordering {
1601 for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
1602 if a < b {
1603 return ::core::cmp::Ordering::Less
1604 } else if a > b {
1605 return ::core::cmp::Ordering::Greater
1606 }
1607 }
1608
1609 ::core::cmp::Ordering::Equal
1610 }
1611
1612 #[inline(always)]
1615 #[cfg(not(target_os = "zkvm"))]
1616 fn is_valid(&self) -> bool {
1617 self.cmp_native(&MODULUS_LIMBS) == ::core::cmp::Ordering::Less
1620 }
1621
1622 #[inline(always)]
1623 #[cfg(not(target_os = "zkvm"))]
1624 fn add_nocarry(&mut self, other: &#name) {
1625 let mut carry = 0;
1626
1627 for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
1628 let (new_a, new_carry) = ::ff::derive::adc(*a, *b, carry);
1629 *a = new_a;
1630 carry = new_carry;
1631 }
1632 }
1633
1634 #[inline(always)]
1635 #[cfg(not(target_os = "zkvm"))]
1636 fn sub_noborrow(&mut self, other: &#name) {
1637 let mut borrow = 0;
1638
1639 for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
1640 let (new_a, new_borrow) = ::ff::derive::sbb(*a, *b, borrow);
1641 *a = new_a;
1642 borrow = new_borrow;
1643 }
1644 }
1645
1646 #[inline(always)]
1649 #[cfg(not(target_os = "zkvm"))]
1650 fn reduce(&mut self) {
1651 if !self.is_valid() {
1652 self.sub_noborrow(&MODULUS_LIMBS);
1653 }
1654 }
1655
1656 #[allow(clippy::too_many_arguments)]
1657 #[inline(always)]
1658 #[cfg(not(target_os = "zkvm"))]
1659 fn mont_reduce(
1660 &mut self,
1661 #mont_paramlist
1662 )
1663 {
1664 #montgomery_impl
1669
1670 self.reduce();
1671 }
1672
1673 #[cfg(target_os = "zkvm")]
1675 fn constant_time_is_reduced(&self) -> ::ff::derive::subtle::Choice {
1676 let mut is_less = 0u8.into();
1677 for (x_limb, p_limb) in self.0.iter().zip(<Self as ::openvm_algebra_guest::IntMod>::MODULUS.iter()) {
1679 if x_limb < p_limb {
1680 is_less = 1u8.into();
1681 } else if x_limb > p_limb {
1682 is_less = 0u8.into();
1683 }
1684 }
1685 is_less
1687 }
1688 }
1689 }
1690}