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_bigint03::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; {limbs}]`",
319 ),
320 )
321 .to_compile_error(),
322 )
323 }
324 };
325
326 if match arr.elem.as_ref() {
328 syn::Type::Path(path) => path.path.get_ident().map(|x| *x != "u64").unwrap_or(true),
329 _ => true,
330 } {
331 return Some(
332 syn::Error::new_spanned(
333 arr,
334 format!("PrimeField derive requires 64-bit limbs. Change this to `[u64; {limbs}]"),
335 )
336 .to_compile_error(),
337 );
338 }
339
340 let expr_lit = match &arr.len {
342 syn::Expr::Lit(expr_lit) => Some(&expr_lit.lit),
343 syn::Expr::Group(expr_group) => match &*expr_group.expr {
344 syn::Expr::Lit(expr_lit) => Some(&expr_lit.lit),
345 _ => None,
346 },
347 _ => None,
348 };
349 let lit_int = match match expr_lit {
350 Some(syn::Lit::Int(lit_int)) => Some(lit_int),
351 _ => None,
352 } {
353 Some(x) => x,
354 _ => {
355 return Some(
356 syn::Error::new_spanned(
357 arr,
358 format!("To derive PrimeField, change this to `[u64; {limbs}]`."),
359 )
360 .to_compile_error(),
361 )
362 }
363 };
364 if lit_int.base10_digits() != limbs.to_string() {
365 return Some(
366 syn::Error::new_spanned(
367 lit_int,
368 format!("The given modulus requires {limbs} limbs."),
369 )
370 .to_compile_error(),
371 );
372 }
373
374 match &field.vis {
376 syn::Visibility::Inherited => (),
377 _ => {
378 return Some(
379 syn::Error::new_spanned(&field.vis, "Field must not be public.").to_compile_error(),
380 )
381 }
382 }
383
384 None
386}
387
388fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option<String> {
390 for attr in attrs {
391 if let Ok(meta) = attr.parse_meta() {
392 match meta {
393 syn::Meta::NameValue(nv) => {
394 if nv.path.get_ident().map(|i| i.to_string()) == Some(name.to_string()) {
395 match nv.lit {
396 syn::Lit::Str(ref s) => return Some(s.value()),
397 _ => {
398 panic!("attribute {name} should be a string");
399 }
400 }
401 }
402 }
403 _ => {
404 panic!("attribute {name} should be a string");
405 }
406 }
407 }
408 }
409
410 None
411}
412
413fn prime_field_repr_impl(
415 repr: &syn::Ident,
416 endianness: &ReprEndianness,
417 bytes: usize,
418) -> proc_macro2::TokenStream {
419 let repr_iter_be = endianness.iter_be();
420
421 quote! {
422 #[derive(Copy, Clone)]
423 pub struct #repr(pub [u8; #bytes]);
424
425 impl ::ff::derive::subtle::ConstantTimeEq for #repr {
426 fn ct_eq(&self, other: &#repr) -> ::ff::derive::subtle::Choice {
427 self.0
428 .iter()
429 .zip(other.0.iter())
430 .map(|(a, b)| a.ct_eq(b))
431 .fold(1.into(), |acc, x| acc & x)
432 }
433 }
434
435 impl ::core::cmp::PartialEq for #repr {
436 fn eq(&self, other: &#repr) -> bool {
437 use ::ff::derive::subtle::ConstantTimeEq;
438 self.ct_eq(other).into()
439 }
440 }
441
442 impl ::core::cmp::Eq for #repr { }
443
444 impl ::core::default::Default for #repr {
445 fn default() -> #repr {
446 #repr([0u8; #bytes])
447 }
448 }
449
450 impl ::core::fmt::Debug for #repr
451 {
452 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
453 write!(f, "0x")?;
454 for i in #repr_iter_be {
455 write!(f, "{:02x}", *i)?;
456 }
457
458 Ok(())
459 }
460 }
461
462 impl AsRef<[u8]> for #repr {
463 #[inline(always)]
464 fn as_ref(&self) -> &[u8] {
465 &self.0
466 }
467 }
468
469 impl AsMut<[u8]> for #repr {
470 #[inline(always)]
471 fn as_mut(&mut self) -> &mut [u8] {
472 &mut self.0
473 }
474 }
475 }
476}
477
478fn biguint_to_real_u64_vec(mut v: BigUint, limbs: usize) -> Vec<u64> {
480 let m = BigUint::one() << 64;
481 let mut ret = vec![];
482
483 while v > BigUint::zero() {
484 let limb: BigUint = &v % &m;
485 ret.push(limb.to_u64().unwrap());
486 v >>= 64;
487 }
488
489 while ret.len() < limbs {
490 ret.push(0);
491 }
492
493 assert!(ret.len() == limbs);
494
495 ret
496}
497
498fn biguint_to_u64_vec(v: BigUint, limbs: usize) -> proc_macro2::TokenStream {
500 let ret = biguint_to_real_u64_vec(v, limbs);
501 quote!([#(#ret,)*])
502}
503
504fn biguint_to_u8_vec(v: BigUint, limbs: usize) -> proc_macro2::TokenStream {
506 let mut bytes = v.to_bytes_le();
507 while bytes.len() < limbs {
508 bytes.push(0);
509 }
510 quote!([#(#bytes,)*])
511}
512
513fn biguint_num_bits(mut v: BigUint) -> u32 {
514 let mut bits = 0;
515
516 while v != BigUint::zero() {
517 v >>= 1;
518 bits += 1;
519 }
520
521 bits
522}
523
524fn exp(base: BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
526 let mut ret = BigUint::one();
527
528 for i in exp
529 .to_bytes_be()
530 .into_iter()
531 .flat_map(|x| (0..8).rev().map(move |i| (x >> i).is_odd()))
532 {
533 ret = (&ret * &ret) % modulus;
534 if i {
535 ret = (ret * &base) % modulus;
536 }
537 }
538
539 ret
540}
541
542#[test]
543fn test_exp() {
544 assert_eq!(
545 exp(
546 BigUint::from_str("4398572349857239485729348572983472345").unwrap(),
547 &BigUint::from_str("5489673498567349856734895").unwrap(),
548 &BigUint::from_str(
549 "52435875175126190479447740508185965837690552500527637822603658699938581184513"
550 )
551 .unwrap()
552 ),
553 BigUint::from_str(
554 "4371221214068404307866768905142520595925044802278091865033317963560480051536"
555 )
556 .unwrap()
557 );
558}
559
560fn prime_field_constants_and_sqrt(
561 name: &syn::Ident,
562 modulus: &BigUint,
563 limbs: usize,
564 zkvm_limbs: usize,
565 generator: BigUint,
566) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
567 let bytes = limbs * 8;
568 let modulus_num_bits = biguint_num_bits(modulus.clone());
569
570 let repr_shave_bits = (64 * limbs as u32) - biguint_num_bits(modulus.clone());
575
576 let r = (BigUint::one() << (limbs * 64)) % modulus;
578 let to_mont = |v| (v * &r) % modulus;
579
580 let two = BigUint::from_str("2").unwrap();
581 let p_minus_2 = modulus - &two;
582 let invert = |v| exp(v, &p_minus_2, modulus);
583
584 let two_inv = biguint_to_u64_vec(to_mont(invert(two.clone())), limbs);
586 let two_inv_bytes = biguint_to_u8_vec(invert(two), zkvm_limbs);
587
588 let mut s: u32 = 0;
590 let mut t = modulus - BigUint::from_str("1").unwrap();
591 while t.is_even() {
592 t >>= 1;
593 s += 1;
594 }
595
596 let root_of_unity_biguint = exp(generator.clone(), &t, modulus);
598
599 let root_of_unity_inv_biguint = invert(root_of_unity_biguint.clone());
600 let root_of_unity_inv = biguint_to_u64_vec(to_mont(root_of_unity_inv_biguint.clone()), limbs);
601 let root_of_unity_inv_bytes = biguint_to_u8_vec(root_of_unity_inv_biguint, zkvm_limbs);
602
603 let root_of_unity = biguint_to_u64_vec(to_mont(root_of_unity_biguint.clone()), limbs);
604 let root_of_unity_bytes = biguint_to_u8_vec(root_of_unity_biguint, zkvm_limbs);
605
606 let delta_biguint = exp(generator.clone(), &(BigUint::one() << s), modulus);
607 let delta = biguint_to_u64_vec(to_mont(delta_biguint.clone()), limbs);
608 let delta_bytes = biguint_to_u8_vec(delta_biguint, zkvm_limbs);
609
610 let generator_u64_limbs = biguint_to_u64_vec(to_mont(generator.clone()), limbs);
611 let generator_bytes = biguint_to_u8_vec(generator, zkvm_limbs);
612
613 let sqrt_impl =
614 if (modulus % BigUint::from_str("4").unwrap()) == BigUint::from_str("3").unwrap() {
615 let mod_plus_1_over_4 = pow_fixed::generate(
617 "e! {self},
618 (modulus + BigUint::from_str("1").unwrap()) >> 2,
619 );
620
621 quote! {
622 use ::ff::derive::subtle::ConstantTimeEq;
623
624 let sqrt = {
628 #mod_plus_1_over_4
629 };
630
631 ::ff::derive::subtle::CtOption::new(
632 sqrt,
633 (sqrt * &sqrt).ct_eq(self), )
635 }
636 } else {
637 let t_minus_1_over_2 = if t == BigUint::one() {
639 quote!( #name::ONE )
640 } else {
641 pow_fixed::generate("e! {self}, (&t - BigUint::one()) >> 1)
642 };
643
644 quote! {
645 use ::ff::derive::subtle::{ConditionallySelectable, ConstantTimeEq};
648
649 let w = {
651 #t_minus_1_over_2
652 };
653
654 let mut v = S;
655 let mut x = *self * &w;
656 let mut b = x * &w;
657
658 let mut z = ROOT_OF_UNITY;
660
661 for max_v in (1..=S).rev() {
662 let mut k = 1;
663 let mut tmp = b.square();
664 let mut j_less_than_v: ::ff::derive::subtle::Choice = 1.into();
665
666 for j in 2..max_v {
667 let tmp_is_one = tmp.ct_eq(&#name::ONE);
668 let squared = #name::conditional_select(&tmp, &z, tmp_is_one).square();
669 tmp = #name::conditional_select(&squared, &tmp, tmp_is_one);
670 let new_z = #name::conditional_select(&z, &squared, tmp_is_one);
671 j_less_than_v &= !j.ct_eq(&v);
672 k = u32::conditional_select(&j, &k, tmp_is_one);
673 z = #name::conditional_select(&z, &new_z, j_less_than_v);
674 }
675
676 let result = x * &z;
677 x = #name::conditional_select(&result, &x, b.ct_eq(&#name::ONE));
678 z = z.square();
679 b *= &z;
680 v = k;
681 }
682
683 ::ff::derive::subtle::CtOption::new(
684 x,
685 (x * &x).ct_eq(self), )
687 }
688 };
689
690 let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs);
692
693 let r = biguint_to_u64_vec(r, limbs);
694 let modulus_le_bytes = ReprEndianness::Little.modulus_repr(modulus, limbs * 8);
695 let modulus_str = format!("0x{}", modulus.to_str_radix(16));
696 let modulus = biguint_to_real_u64_vec(modulus.clone(), limbs);
697
698 let mut inv = 1u64;
700 for _ in 0..63 {
701 inv = inv.wrapping_mul(inv);
702 inv = inv.wrapping_mul(modulus[0]);
703 }
704 inv = inv.wrapping_neg();
705
706 (
707 quote! {
708 type REPR_BYTES = [u8; #bytes];
709 type REPR_BITS = REPR_BYTES;
710
711 const MODULUS: REPR_BITS = [#(#modulus_le_bytes,)*];
713
714 #[cfg(not(target_os = "zkvm"))]
716 const MODULUS_LIMBS: #name = #name([#(#modulus,)*]);
717
718 const MODULUS_STR: &'static str = #modulus_str;
720
721 const MODULUS_BITS: u32 = #modulus_num_bits;
723
724 const REPR_SHAVE_BITS: u32 = #repr_shave_bits;
727
728 #[cfg(not(target_os = "zkvm"))]
730 const R: #name = #name(#r);
731
732 #[cfg(not(target_os = "zkvm"))]
734 const R2: #name = #name(#r2);
735
736 #[cfg(not(target_os = "zkvm"))]
738 const INV: u64 = #inv;
739
740 #[cfg(target_os = "zkvm")]
742 const TWO_INV: #name = <#name>::from_const_bytes(#two_inv_bytes);
743 #[cfg(not(target_os = "zkvm"))]
744 const TWO_INV: #name = #name(#two_inv);
745
746 #[cfg(target_os = "zkvm")]
749 const GENERATOR: #name = <#name>::from_const_bytes(#generator_bytes);
750 #[cfg(not(target_os = "zkvm"))]
751 const GENERATOR: #name = #name(#generator_u64_limbs);
752
753 const S: u32 = #s;
755
756 #[cfg(target_os = "zkvm")]
758 const ROOT_OF_UNITY: #name = <#name>::from_const_bytes(#root_of_unity_bytes);
759 #[cfg(not(target_os = "zkvm"))]
760 const ROOT_OF_UNITY: #name = #name(#root_of_unity);
761
762 #[cfg(target_os = "zkvm")]
764 const ROOT_OF_UNITY_INV: #name = <#name>::from_const_bytes(#root_of_unity_inv_bytes);
765 #[cfg(not(target_os = "zkvm"))]
766 const ROOT_OF_UNITY_INV: #name = #name(#root_of_unity_inv);
767
768 #[cfg(target_os = "zkvm")]
770 const DELTA: #name = <#name>::from_const_bytes(#delta_bytes);
771 #[cfg(not(target_os = "zkvm"))]
772 const DELTA: #name = #name(#delta);
773 },
774 sqrt_impl,
775 )
776}
777
778fn prime_field_impl(
780 name: &syn::Ident,
781 repr: &syn::Ident,
782 modulus: &BigUint,
783 endianness: &ReprEndianness,
784 limbs: usize,
785 zkvm_limbs: usize,
786 sqrt_impl: proc_macro2::TokenStream,
787) -> proc_macro2::TokenStream {
788 fn get_temp(n: usize) -> syn::Ident {
790 syn::Ident::new(&format!("r{n}"), proc_macro2::Span::call_site())
791 }
792
793 let mut mont_paramlist = proc_macro2::TokenStream::new();
796 mont_paramlist.append_separated(
797 (0..(limbs * 2)).map(|i| (i, get_temp(i))).map(|(i, x)| {
798 if i != 0 {
799 quote! {mut #x: u64}
800 } else {
801 quote! {#x: u64}
802 }
803 }),
804 proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
805 );
806
807 fn mont_impl(limbs: usize) -> proc_macro2::TokenStream {
809 #[cfg(target_os = "zkvm")]
810 {
811 quote! {
812 unimplemented!();
813 }
814 }
815 #[cfg(not(target_os = "zkvm"))]
816 {
817 let mut gen = proc_macro2::TokenStream::new();
818
819 for i in 0..limbs {
820 {
821 let temp = get_temp(i);
822 gen.extend(quote! {
823 let k = #temp.wrapping_mul(INV);
824 let (_, carry) = ::ff::derive::mac(#temp, k, MODULUS_LIMBS.0[0], 0);
825 });
826 }
827
828 for j in 1..limbs {
829 let temp = get_temp(i + j);
830 gen.extend(quote! {
831 let (#temp, carry) = ::ff::derive::mac(#temp, k, MODULUS_LIMBS.0[#j], carry);
832 });
833 }
834
835 let temp = get_temp(i + limbs);
836
837 if i == 0 {
838 gen.extend(quote! {
839 let (#temp, carry2) = ::ff::derive::adc(#temp, 0, carry);
840 });
841 } else {
842 gen.extend(quote! {
843 let (#temp, carry2) = ::ff::derive::adc(#temp, carry2, carry);
844 });
845 }
846 }
847
848 for i in 0..limbs {
849 let temp = get_temp(limbs + i);
850
851 gen.extend(quote! {
852 self.0[#i] = #temp;
853 });
854 }
855
856 gen
857 }
858 }
859
860 fn sqr_impl(a: proc_macro2::TokenStream, limbs: usize) -> proc_macro2::TokenStream {
861 let mut gen = proc_macro2::TokenStream::new();
862
863 if limbs > 1 {
864 for i in 0..(limbs - 1) {
865 gen.extend(quote! {
866 let carry = 0;
867 });
868
869 for j in (i + 1)..limbs {
870 let temp = get_temp(i + j);
871 if i == 0 {
872 gen.extend(quote! {
873 let (#temp, carry) = ::ff::derive::mac(0, #a.0[#i], #a.0[#j], carry);
874 });
875 } else {
876 gen.extend(quote! {
877 let (#temp, carry) = ::ff::derive::mac(#temp, #a.0[#i], #a.0[#j], carry);
878 });
879 }
880 }
881
882 let temp = get_temp(i + limbs);
883
884 gen.extend(quote! {
885 let #temp = carry;
886 });
887 }
888
889 for i in 1..(limbs * 2) {
890 let temp0 = get_temp(limbs * 2 - i);
891 let temp1 = get_temp(limbs * 2 - i - 1);
892
893 if i == 1 {
894 gen.extend(quote! {
895 let #temp0 = #temp1 >> 63;
896 });
897 } else if i == (limbs * 2 - 1) {
898 gen.extend(quote! {
899 let #temp0 = #temp0 << 1;
900 });
901 } else {
902 gen.extend(quote! {
903 let #temp0 = (#temp0 << 1) | (#temp1 >> 63);
904 });
905 }
906 }
907 } else {
908 let temp1 = get_temp(1);
909 gen.extend(quote! {
910 let #temp1 = 0;
911 });
912 }
913
914 for i in 0..limbs {
915 let temp0 = get_temp(i * 2);
916 let temp1 = get_temp(i * 2 + 1);
917 if i == 0 {
918 gen.extend(quote! {
919 let (#temp0, carry) = ::ff::derive::mac(0, #a.0[#i], #a.0[#i], 0);
920 });
921 } else {
922 gen.extend(quote! {
923 let (#temp0, carry) = ::ff::derive::mac(#temp0, #a.0[#i], #a.0[#i], carry);
924 });
925 }
926
927 gen.extend(quote! {
928 let (#temp1, carry) = ::ff::derive::adc(#temp1, 0, carry);
929 });
930 }
931
932 let mut mont_calling = proc_macro2::TokenStream::new();
933 mont_calling.append_separated(
934 (0..(limbs * 2)).map(get_temp),
935 proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
936 );
937
938 gen.extend(quote! {
939 let mut ret = *self;
940 ret.mont_reduce(#mont_calling);
941 ret
942 });
943
944 gen
945 }
946
947 fn mul_impl(
948 a: proc_macro2::TokenStream,
949 b: proc_macro2::TokenStream,
950 limbs: usize,
951 ) -> proc_macro2::TokenStream {
952 let mut gen = proc_macro2::TokenStream::new();
953
954 for i in 0..limbs {
955 gen.extend(quote! {
956 let carry = 0;
957 });
958
959 for j in 0..limbs {
960 let temp = get_temp(i + j);
961
962 if i == 0 {
963 gen.extend(quote! {
964 let (#temp, carry) = ::ff::derive::mac(0, #a.0[#i], #b.0[#j], carry);
965 });
966 } else {
967 gen.extend(quote! {
968 let (#temp, carry) = ::ff::derive::mac(#temp, #a.0[#i], #b.0[#j], carry);
969 });
970 }
971 }
972
973 let temp = get_temp(i + limbs);
974
975 gen.extend(quote! {
976 let #temp = carry;
977 });
978 }
979
980 let mut mont_calling = proc_macro2::TokenStream::new();
981 mont_calling.append_separated(
982 (0..(limbs * 2)).map(get_temp),
983 proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
984 );
985
986 gen.extend(quote! {
987 self.mont_reduce(#mont_calling);
988 });
989
990 gen
991 }
992
993 fn inv_impl(a: proc_macro2::TokenStream, modulus: &BigUint) -> proc_macro2::TokenStream {
996 let mod_minus_2 = pow_fixed::generate(&a, modulus - BigUint::from(2u64));
998
999 quote! {
1000 use ::ff::derive::subtle::ConstantTimeEq;
1001
1002 let inv = {
1009 #mod_minus_2
1010 };
1011
1012 ::ff::derive::subtle::CtOption::new(inv, !#a.is_zero())
1013 }
1014 }
1015
1016 let squaring_impl = sqr_impl(quote! {self}, limbs);
1017 let multiply_impl = mul_impl(quote! {self}, quote! {other}, limbs);
1018 let invert_impl = inv_impl(quote! {self}, modulus);
1019 let montgomery_impl = mont_impl(limbs);
1020
1021 fn mont_reduce_params(a: proc_macro2::TokenStream, limbs: usize) -> proc_macro2::TokenStream {
1022 let mut mont_reduce_params = proc_macro2::TokenStream::new();
1024 mont_reduce_params.append_separated(
1025 (0..limbs)
1026 .map(|i| quote! { #a.0[#i] })
1027 .chain((0..limbs).map(|_| quote! {0})),
1028 proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
1029 );
1030 mont_reduce_params
1031 }
1032
1033 let mont_reduce_self_params = mont_reduce_params(quote! {self}, limbs);
1034 let mont_reduce_other_params = mont_reduce_params(quote! {other}, limbs);
1035
1036 let from_repr_impl = endianness.from_repr(name, limbs);
1037 let to_repr_impl = endianness.to_repr(quote! {#repr}, &mont_reduce_self_params, limbs);
1038
1039 let prime_field_bits_impl = if cfg!(feature = "bits") {
1040 let to_le_bits_impl = ReprEndianness::Little.to_repr(
1041 quote! {::ff::derive::bitvec::array::BitArray::new},
1042 &mont_reduce_self_params,
1043 limbs,
1044 );
1045
1046 Some(quote! {
1047 impl ::ff::PrimeFieldBits for #name {
1048 type ReprBits = REPR_BITS;
1049
1050 fn to_le_bits(&self) -> ::ff::FieldBits<REPR_BITS> {
1051 #to_le_bits_impl
1052 }
1053
1054 fn char_le_bits() -> ::ff::FieldBits<REPR_BITS> {
1055 ::ff::FieldBits::new(MODULUS)
1056 }
1057 }
1058 })
1059 } else {
1060 None
1061 };
1062
1063 let top_limb_index = limbs - 1;
1064
1065 let impl_module_ident =
1069 syn::Ident::new(&format!("impl_{name}"), proc_macro2::Span::call_site());
1070
1071 let zero_impl = quote! {
1072 #[cfg(target_os = "zkvm")]
1073 const ZERO: Self = <Self as ::openvm_algebra_guest::IntMod>::ZERO;
1074 #[cfg(not(target_os = "zkvm"))]
1075 const ZERO: Self = #name([0; #limbs]);
1076 };
1077 let one_impl = quote! {
1078 #[cfg(target_os = "zkvm")]
1079 const ONE: Self = <Self as ::openvm_algebra_guest::IntMod>::ONE;
1080 #[cfg(not(target_os = "zkvm"))]
1081 const ONE: Self = R;
1082 };
1083
1084 quote! {
1085 impl ::core::marker::Copy for #name { }
1086
1087 impl ::core::default::Default for #name {
1088 fn default() -> #name {
1089 use ::ff::Field;
1090 #name::ZERO
1091 }
1092 }
1093
1094 impl ::ff::derive::subtle::ConstantTimeEq for #name {
1095 fn ct_eq(&self, other: &#name) -> ::ff::derive::subtle::Choice {
1102 use ::ff::PrimeField;
1103 self.to_repr().ct_eq(&other.to_repr())
1104 }
1105 }
1106
1107 impl Ord for #name {
1109 #[inline(always)]
1110 fn cmp(&self, other: &#name) -> ::core::cmp::Ordering {
1111 #[cfg(target_os = "zkvm")]
1112 {
1113 <Self as ::openvm_algebra_guest::IntMod>::assert_reduced(self);
1114 <Self as ::openvm_algebra_guest::IntMod>::assert_reduced(other);
1115
1116 self.cmp_native(other)
1117 }
1118 #[cfg(not(target_os = "zkvm"))]
1119 {
1120 let mut a = *self;
1121 a.mont_reduce(
1122 #mont_reduce_self_params
1123 );
1124
1125 let mut b = *other;
1126 b.mont_reduce(
1127 #mont_reduce_other_params
1128 );
1129
1130 a.cmp_native(&b)
1131 }
1132 }
1133 }
1134
1135 impl PartialOrd for #name {
1136 #[inline(always)]
1137 fn partial_cmp(&self, other: &#name) -> Option<::core::cmp::Ordering> {
1138 Some(self.cmp(other))
1139 }
1140 }
1141
1142 impl From<u64> for #name {
1143 #[inline(always)]
1144 fn from(val: u64) -> #name {
1145 #[cfg(target_os = "zkvm")]
1146 {
1147 <#name as ::openvm_algebra_guest::IntMod>::from_u64(val)
1148 }
1149 #[cfg(not(target_os = "zkvm"))]
1150 {
1151 let mut raw = [0u64; #limbs];
1152 raw[0] = val;
1153 #name(raw) * R2
1154 }
1155 }
1156 }
1157
1158 impl From<#name> for #repr {
1159 fn from(e: #name) -> #repr {
1160 use ::ff::PrimeField;
1161 e.to_repr()
1162 }
1163 }
1164
1165 impl<'a> From<&'a #name> for #repr {
1166 fn from(e: &'a #name) -> #repr {
1167 use ::ff::PrimeField;
1168 e.to_repr()
1169 }
1170 }
1171
1172 impl ::ff::derive::subtle::ConditionallySelectable for #name {
1173 fn conditional_select(a: &#name, b: &#name, choice: ::ff::derive::subtle::Choice) -> #name {
1174 #[cfg(target_os = "zkvm")]
1175 {
1176 let mut res = [0u8; #zkvm_limbs];
1177 let a_le_bytes = <Self as ::openvm_algebra_guest::IntMod>::as_le_bytes(a);
1178 let b_le_bytes = <Self as ::openvm_algebra_guest::IntMod>::as_le_bytes(b);
1179 for i in 0..#zkvm_limbs {
1180 res[i] = u8::conditional_select(&a_le_bytes[i], &b_le_bytes[i], choice);
1181 }
1182 #name(res)
1183 }
1184 #[cfg(not(target_os = "zkvm"))]
1185 {
1186 let mut res = [0u64; #limbs];
1187 for i in 0..#limbs {
1188 res[i] = u64::conditional_select(&a.0[i], &b.0[i], choice);
1189 }
1190 #name(res)
1191 }
1192 }
1193 }
1194
1195 #[cfg(not(target_os = "zkvm"))]
1198 mod #impl_module_ident {
1199 use super::{#name, MODULUS_LIMBS};
1200
1201 impl ::core::clone::Clone for #name {
1202 fn clone(&self) -> #name {
1203 *self
1204 }
1205 }
1206
1207 impl ::core::cmp::PartialEq for #name {
1208 fn eq(&self, other: &#name) -> bool {
1209 use ::ff::derive::subtle::ConstantTimeEq;
1210 self.ct_eq(other).into()
1211 }
1212 }
1213
1214 impl ::core::cmp::Eq for #name { }
1215
1216 impl ::core::fmt::Debug for #name
1217 {
1218 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
1219 use ::ff::PrimeField;
1220 write!(f, "{}({:?})", stringify!(#name), self.to_repr())
1221 }
1222 }
1223
1224
1225 impl ::core::ops::Neg for #name {
1226 type Output = #name;
1227
1228 #[inline]
1229 fn neg(self) -> #name {
1230 use ::ff::Field;
1231
1232 let mut ret = self;
1233 if !ret.is_zero_vartime() {
1234 let mut tmp = MODULUS_LIMBS;
1235 tmp.sub_noborrow(&ret);
1236 ret = tmp;
1237 }
1238 ret
1239 }
1240 }
1241
1242 impl<'r> ::core::ops::Add<&'r #name> for #name {
1243 type Output = #name;
1244
1245 #[inline]
1246 fn add(self, other: &#name) -> #name {
1247 use ::core::ops::AddAssign;
1248
1249 let mut ret = self;
1250 ret.add_assign(other);
1251 ret
1252 }
1253 }
1254
1255 impl ::core::ops::Add for #name {
1256 type Output = #name;
1257
1258 #[inline]
1259 fn add(self, other: #name) -> Self {
1260 self + &other
1261 }
1262 }
1263
1264 impl<'r> ::core::ops::AddAssign<&'r #name> for #name {
1265 #[inline]
1266 fn add_assign(&mut self, other: &#name) {
1267 self.add_nocarry(other);
1269
1270 self.reduce();
1272 }
1273 }
1274
1275 impl ::core::ops::AddAssign for #name {
1276 #[inline]
1277 fn add_assign(&mut self, other: #name) {
1278 self.add_assign(&other);
1279 }
1280 }
1281
1282 impl<'r> ::core::ops::Sub<&'r #name> for #name {
1283 type Output = #name;
1284
1285 #[inline]
1286 fn sub(self, other: &#name) -> Self {
1287 use ::core::ops::SubAssign;
1288
1289 let mut ret = self;
1290 ret.sub_assign(other);
1291 ret
1292 }
1293 }
1294
1295 impl ::core::ops::Sub for #name {
1296 type Output = #name;
1297
1298 #[inline]
1299 fn sub(self, other: #name) -> Self {
1300 self - &other
1301 }
1302 }
1303
1304 impl<'r> ::core::ops::SubAssign<&'r #name> for #name {
1305 #[inline]
1306 fn sub_assign(&mut self, other: &#name) {
1307 if other.cmp_native(self) == ::core::cmp::Ordering::Greater {
1309 self.add_nocarry(&MODULUS_LIMBS);
1310 }
1311
1312 self.sub_noborrow(other);
1313 }
1314 }
1315
1316 impl ::core::ops::SubAssign for #name {
1317 #[inline]
1318 fn sub_assign(&mut self, other: #name) {
1319 self.sub_assign(&other);
1320 }
1321 }
1322
1323 impl<'r> ::core::ops::Mul<&'r #name> for #name {
1324 type Output = #name;
1325
1326 #[inline]
1327 fn mul(self, other: &#name) -> Self {
1328 use ::core::ops::MulAssign;
1329
1330 let mut ret = self;
1331 ret.mul_assign(other);
1332 ret
1333 }
1334 }
1335
1336 impl ::core::ops::Mul for #name {
1337 type Output = #name;
1338
1339 #[inline]
1340 fn mul(self, other: #name) -> Self {
1341 self * &other
1342 }
1343 }
1344
1345 impl<'r> ::core::ops::MulAssign<&'r #name> for #name {
1346 #[inline]
1347 fn mul_assign(&mut self, other: &#name)
1348 {
1349 #multiply_impl
1350 }
1351 }
1352
1353 impl ::core::ops::MulAssign for #name {
1354 #[inline]
1355 fn mul_assign(&mut self, other: #name)
1356 {
1357 self.mul_assign(&other);
1358 }
1359 }
1360
1361 impl<T: ::core::borrow::Borrow<#name>> ::core::iter::Sum<T> for #name {
1362 fn sum<I: Iterator<Item = T>>(iter: I) -> Self {
1363 use ::ff::Field;
1364
1365 iter.fold(Self::ZERO, |acc, item| acc + item.borrow())
1366 }
1367 }
1368
1369 impl<T: ::core::borrow::Borrow<#name>> ::core::iter::Product<T> for #name {
1370 fn product<I: Iterator<Item = T>>(iter: I) -> Self {
1371 use ::ff::Field;
1372
1373 iter.fold(Self::ONE, |acc, item| acc * item.borrow())
1374 }
1375 }
1376 }
1377
1378 impl ::ff::PrimeField for #name {
1379 type Repr = #repr;
1380
1381 fn from_repr(r: #repr) -> ::ff::derive::subtle::CtOption<#name> {
1382 #from_repr_impl
1383
1384 #[cfg(target_os = "zkvm")]
1385 {
1386 ::ff::derive::subtle::CtOption::new(r, r.constant_time_is_reduced())
1387 }
1388 #[cfg(not(target_os = "zkvm"))]
1389 {
1390 let borrow = r.0.iter().zip(MODULUS_LIMBS.0.iter()).fold(0, |borrow, (a, b)| {
1392 ::ff::derive::sbb(*a, *b, borrow).1
1393 });
1394
1395 let is_some = ::ff::derive::subtle::Choice::from((borrow as u8) & 1);
1399
1400 ::ff::derive::subtle::CtOption::new(r * &R2, is_some)
1403 }
1404 }
1405
1406 fn from_repr_vartime(r: #repr) -> Option<#name> {
1407 #from_repr_impl
1408
1409 #[cfg(target_os = "zkvm")]
1410 {
1411 if <Self as ::openvm_algebra_guest::IntMod>::is_reduced(&r) {
1412 Some(r)
1413 } else {
1414 None
1415 }
1416 }
1417 #[cfg(not(target_os = "zkvm"))]
1418 {
1419 if r.is_valid() {
1420 Some(r * R2)
1421 } else {
1422 None
1423 }
1424
1425 }
1426 }
1427
1428 fn to_repr(&self) -> #repr {
1429 #to_repr_impl
1430 }
1431
1432 #[inline(always)]
1433 fn is_odd(&self) -> ::ff::derive::subtle::Choice {
1434 #[cfg(target_os = "zkvm")]
1440 {
1441 ::ff::derive::subtle::Choice::from((<Self as ::openvm_algebra_guest::IntMod>::as_le_bytes(self)[0] & 1) as u8)
1442 }
1443 #[cfg(not(target_os = "zkvm"))]
1444 {
1445 let mut r = *self;
1446 r.mont_reduce(
1447 #mont_reduce_self_params
1448 );
1449
1450 ::ff::derive::subtle::Choice::from((r.0[0] & 1) as u8)
1453 }
1454 }
1455
1456 const MODULUS: &'static str = MODULUS_STR;
1457
1458 const NUM_BITS: u32 = MODULUS_BITS;
1459
1460 const CAPACITY: u32 = Self::NUM_BITS - 1;
1461
1462 const TWO_INV: Self = TWO_INV;
1463
1464 const MULTIPLICATIVE_GENERATOR: Self = GENERATOR;
1465
1466 const S: u32 = S;
1467
1468 const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
1469
1470 const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
1471
1472 const DELTA: Self = DELTA;
1473 }
1474
1475 #prime_field_bits_impl
1476
1477 impl ::ff::Field for #name {
1478 #zero_impl
1479 #one_impl
1480
1481 fn random(mut rng: impl ::ff::derive::rand_core::RngCore) -> Self {
1483 #[cfg(target_os = "zkvm")]
1484 {
1485 panic!("randomn is not implemented for the zkvm");
1486 }
1487 #[cfg(not(target_os = "zkvm"))]
1488 {
1489 loop {
1490 let mut tmp = {
1491 let mut repr = [0u64; #limbs];
1492 for i in 0..#limbs {
1493 repr[i] = rng.next_u64();
1494 }
1495 #name(repr)
1496 };
1497
1498 tmp.0[#top_limb_index] &= 0xffffffffffffffffu64.checked_shr(REPR_SHAVE_BITS).unwrap_or(0);
1504
1505 if tmp.is_valid() {
1506 return tmp
1507 }
1508 }
1509 }
1510 }
1511
1512 #[inline]
1513 fn is_zero_vartime(&self) -> bool {
1514 #[cfg(target_os = "zkvm")]
1515 {
1516 self == &Self::ZERO
1517 }
1518 #[cfg(not(target_os = "zkvm"))]
1519 {
1520 self.0.iter().all(|&e| e == 0)
1521 }
1522 }
1523
1524 #[inline]
1525 fn double(&self) -> Self {
1526 #[cfg(target_os = "zkvm")]
1527 {
1528 <Self as ::openvm_algebra_guest::IntMod>::double(self)
1529 }
1530 #[cfg(not(target_os = "zkvm"))]
1531 {
1532 let mut ret = *self;
1533
1534 let mut last = 0;
1536 for i in &mut ret.0 {
1537 let tmp = *i >> 63;
1538 *i <<= 1;
1539 *i |= last;
1540 last = tmp;
1541 }
1542
1543 ret.reduce();
1545
1546 ret
1547 }
1548 }
1549
1550 fn invert(&self) -> ::ff::derive::subtle::CtOption<Self> {
1552 #[cfg(target_os = "zkvm")]
1553 {
1554 let is_self_zero = self.is_zero_vartime();
1555 let res = if is_self_zero {
1556 <Self as ::openvm_algebra_guest::IntMod>::ZERO
1557 } else {
1558 use ::openvm_algebra_guest::DivUnsafe;
1559 <Self as ::openvm_algebra_guest::IntMod>::ONE.div_unsafe(self)
1560 };
1561 ::ff::derive::subtle::CtOption::new(res, (!is_self_zero as u8).into())
1562 }
1563 #[cfg(not(target_os = "zkvm"))]
1564 {
1565 #invert_impl
1566 }
1567 }
1568
1569 #[inline]
1570 fn square(&self) -> Self
1571 {
1572 #[cfg(target_os = "zkvm")]
1573 {
1574 <Self as ::openvm_algebra_guest::IntMod>::square(self)
1575 }
1576 #[cfg(not(target_os = "zkvm"))]
1577 {
1578 #squaring_impl
1579 }
1580 }
1581
1582 fn sqrt_ratio(num: &Self, div: &Self) -> (::ff::derive::subtle::Choice, Self) {
1583 ::ff::helpers::sqrt_ratio_generic(num, div)
1584 }
1585
1586 fn sqrt(&self) -> ::ff::derive::subtle::CtOption<Self> {
1588 #[cfg(target_os = "zkvm")]
1589 {
1590 use ::openvm_algebra_guest::Sqrt;
1591 match Sqrt::sqrt(self) {
1592 Some(sqrt) => ::ff::derive::subtle::CtOption::new(sqrt, 1u8.into()),
1593 None => ::ff::derive::subtle::CtOption::new(Self::ZERO, 0u8.into()),
1594 }
1595 }
1596 #[cfg(not(target_os = "zkvm"))]
1597 {
1598 #sqrt_impl
1599 }
1600 }
1601 }
1602
1603 impl #name {
1604 #[inline(always)]
1607 fn cmp_native(&self, other: &#name) -> ::core::cmp::Ordering {
1608 for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
1609 if a < b {
1610 return ::core::cmp::Ordering::Less
1611 } else if a > b {
1612 return ::core::cmp::Ordering::Greater
1613 }
1614 }
1615
1616 ::core::cmp::Ordering::Equal
1617 }
1618
1619 #[inline(always)]
1622 #[cfg(not(target_os = "zkvm"))]
1623 fn is_valid(&self) -> bool {
1624 self.cmp_native(&MODULUS_LIMBS) == ::core::cmp::Ordering::Less
1627 }
1628
1629 #[inline(always)]
1630 #[cfg(not(target_os = "zkvm"))]
1631 fn add_nocarry(&mut self, other: &#name) {
1632 let mut carry = 0;
1633
1634 for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
1635 let (new_a, new_carry) = ::ff::derive::adc(*a, *b, carry);
1636 *a = new_a;
1637 carry = new_carry;
1638 }
1639 }
1640
1641 #[inline(always)]
1642 #[cfg(not(target_os = "zkvm"))]
1643 fn sub_noborrow(&mut self, other: &#name) {
1644 let mut borrow = 0;
1645
1646 for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
1647 let (new_a, new_borrow) = ::ff::derive::sbb(*a, *b, borrow);
1648 *a = new_a;
1649 borrow = new_borrow;
1650 }
1651 }
1652
1653 #[inline(always)]
1656 #[cfg(not(target_os = "zkvm"))]
1657 fn reduce(&mut self) {
1658 if !self.is_valid() {
1659 self.sub_noborrow(&MODULUS_LIMBS);
1660 }
1661 }
1662
1663 #[allow(clippy::too_many_arguments)]
1664 #[inline(always)]
1665 #[cfg(not(target_os = "zkvm"))]
1666 fn mont_reduce(
1667 &mut self,
1668 #mont_paramlist
1669 )
1670 {
1671 #montgomery_impl
1676
1677 self.reduce();
1678 }
1679
1680 #[cfg(target_os = "zkvm")]
1682 fn constant_time_is_reduced(&self) -> ::ff::derive::subtle::Choice {
1683 let mut is_less = 0u8.into();
1684 for (x_limb, p_limb) in self.0.iter().zip(<Self as ::openvm_algebra_guest::IntMod>::MODULUS.iter()) {
1686 if x_limb < p_limb {
1687 is_less = 1u8.into();
1688 } else if x_limb > p_limb {
1689 is_less = 0u8.into();
1690 }
1691 }
1692 is_less
1694 }
1695 }
1696 }
1697}