openvm_ff_derive/
lib.rs

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    // Clippy things methods named from_* don't take self as a parameter
49    #[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        // We aren't implementing for zkvm here because this function is only used in the prime
150        // field repr impl which is a plain array of bytes
151        match self {
152            ReprEndianness::Big => quote! {self.0.iter()},
153            ReprEndianness::Little => quote! {self.0.iter().rev()},
154        }
155    }
156}
157
158/// Derive the `PrimeField` trait.
159/// **Warning**: This macro removes the struct definition and inserts our own zkvm-compatible struct
160/// into the token stream.
161/// Currently the memory layout of the new struct will always be either 32 or 48-bytes, where the
162/// smallest that will fit the field's modulus is used. Moduli that are larger than 48-bytes are not
163/// yet supported.
164// Required attributes: PrimeFieldModulus, PrimeFieldGenerator, PrimeFieldReprEndianness
165// Note: In our fork, we changed the macro from a derive macro to an attribute-style macro because
166// we need to be able to remove the struct definition and insert our own into the token stream.
167#[proc_macro_attribute]
168pub fn openvm_prime_field(
169    _: proc_macro::TokenStream,
170    input: proc_macro::TokenStream,
171) -> proc_macro::TokenStream {
172    // Parse the type definition
173    let ast: syn::Item = syn::parse_macro_input!(input);
174
175    // The attribute should be applied to a struct.
176    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    // We're given the modulus p of the prime field
186    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    // We may be provided with a generator of p - 1 order. It is required that this generator be
192    // quadratic nonresidue.
193    // TODO: Compute this ourselves.
194    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    // Field element representations may be in little-endian or big-endian.
200    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    // The arithmetic in this library only works if the modulus*2 is smaller than the backing
206    // representation. Compute the number of 64-bit limbs we need.
207    let mut limbs = 1;
208    {
209        let mod2 = (&modulus) << 1; // modulus * 2
210        let mut cur = BigUint::one() << 64; // always 64-bit limbs for now
211        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        // A limitation of our zkvm implementation is that we only support moduli up to 48 bytes.
224        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    // The struct we're deriving for must be a wrapper around `pub [u64; limbs]`.
233    if let Some(err) = validate_struct(&ast, limbs) {
234        return err.into();
235    }
236
237    // Generate the identifier for the "Repr" type we must construct.
238    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    // Remove the attributes from the struct so we can insert it back into the code
246    ast.attrs.clear();
247
248    // Call moduli_declare! to define the struct
249    let openvm_struct = openvm_struct_impl(&ast, &modulus);
250
251    // TODO: test the non-zkvm case
252    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    // Return the generated impl
275    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
290/// Checks that `body` contains `pub [u64; limbs]`.
291fn validate_struct(ast: &syn::ItemStruct, limbs: usize) -> Option<proc_macro2::TokenStream> {
292    // The struct should contain a single unnamed field.
293    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    // The field should be an array.
311    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    // The array's element type should be `u64`.
328    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    // The array's length should be a literal int equal to `limbs`.
345    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    // The field should not be public.
379    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    // Valid!
389    None
390}
391
392/// Fetch an attribute string from the derived struct.
393fn 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
417// Implement the wrapped ident `repr` with `bytes` bytes.
418fn 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
482/// Convert BigUint into a vector of 64-bit limbs.
483fn 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
502/// Convert BigUint into a tokenized vector of 64-bit limbs.
503fn 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
508/// Returns a token stream containing a little-endian bytes representation of `v`.
509fn 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
528/// BigUint modular exponentiation by square-and-multiply.
529fn 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    // The number of bits we should "shave" from a randomly sampled representation, i.e.,
575    // if our modulus is 381 bits and our representation is 384 bits, we should shave
576    // 3 bits from the beginning of a randomly sampled 384 bit representation to
577    // reduce the cost of rejection sampling.
578    let repr_shave_bits = (64 * limbs as u32) - biguint_num_bits(modulus.clone());
579
580    // Compute R = 2**(64 * limbs) mod m
581    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    // 2^-1 mod m
589    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    // modulus - 1 = 2^s * t
593    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    // Compute 2^s root of unity given the generator
601    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            // Addition chain for (r + 1) // 4
620            let mod_plus_1_over_4 = pow_fixed::generate(
621                &quote! {self},
622                (modulus + BigUint::from_str("1").unwrap()) >> 2,
623            );
624
625            quote! {
626                use ::ff::derive::subtle::ConstantTimeEq;
627
628                // Because r = 3 (mod 4)
629                // sqrt can be done with only one exponentiation,
630                // via the computation of  self^((r + 1) // 4) (mod r)
631                let sqrt = {
632                    #mod_plus_1_over_4
633                };
634
635                ::ff::derive::subtle::CtOption::new(
636                    sqrt,
637                    (sqrt * &sqrt).ct_eq(self), // Only return Some if it's the square root.
638                )
639            }
640        } else {
641            // Addition chain for (t - 1) // 2
642            let t_minus_1_over_2 = if t == BigUint::one() {
643                quote!( #name::ONE )
644            } else {
645                pow_fixed::generate(&quote! {self}, (&t - BigUint::one()) >> 1)
646            };
647
648            quote! {
649                // Tonelli-Shanks algorithm works for every remaining odd prime.
650                // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
651                use ::ff::derive::subtle::{ConditionallySelectable, ConstantTimeEq};
652
653                // w = self^((t - 1) // 2)
654                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                // Initialize z as the 2^S root of unity.
663                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), // Only return Some if it's the square root.
690                )
691            }
692        };
693
694    // Compute R^2 mod m
695    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    // Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1
703    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            /// This is the modulus m of the prime field
716            const MODULUS: REPR_BITS = [#(#modulus_le_bytes,)*];
717
718            /// This is the modulus m of the prime field in limb form
719            #[cfg(not(target_os = "zkvm"))]
720            const MODULUS_LIMBS: #name = #name([#(#modulus,)*]);
721
722            /// This is the modulus m of the prime field in hex string form
723            const MODULUS_STR: &'static str = #modulus_str;
724
725            /// The number of bits needed to represent the modulus.
726            const MODULUS_BITS: u32 = #modulus_num_bits;
727
728            /// The number of bits that must be shaved from the beginning of
729            /// the representation when randomly sampling.
730            const REPR_SHAVE_BITS: u32 = #repr_shave_bits;
731
732            /// 2^{limbs*64} mod m
733            #[cfg(not(target_os = "zkvm"))]
734            const R: #name = #name(#r);
735
736            /// 2^{limbs*64*2} mod m
737            #[cfg(not(target_os = "zkvm"))]
738            const R2: #name = #name(#r2);
739
740            /// -(m^{-1} mod m) mod m
741            #[cfg(not(target_os = "zkvm"))]
742            const INV: u64 = #inv;
743
744            /// 2^{-1} mod m
745            #[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            /// Multiplicative generator of `MODULUS` - 1 order, also quadratic
751            /// nonresidue.
752            #[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            /// 2^s * t = MODULUS - 1 with t odd
758            const S: u32 = #s;
759
760            /// 2^s root of unity computed by GENERATOR^t
761            #[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            /// (2^s)^{-1} mod m
767            #[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            /// GENERATOR^{2^s}
773            #[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
782/// Implement PrimeField for the derived type.
783fn 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    // Returns r{n} as an ident.
793    fn get_temp(n: usize) -> syn::Ident {
794        syn::Ident::new(&format!("r{}", n), proc_macro2::Span::call_site())
795    }
796
797    // The parameter list for the mont_reduce() internal method.
798    // r0: u64, mut r1: u64, mut r2: u64, ...
799    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    // Implement montgomery reduction for some number of limbs
812    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    /// Generates an implementation of multiplicative inversion within the target prime
998    /// field.
999    fn inv_impl(a: proc_macro2::TokenStream, modulus: &BigUint) -> proc_macro2::TokenStream {
1000        // Addition chain for p - 2
1001        let mod_minus_2 = pow_fixed::generate(&a, modulus - BigUint::from(2u64));
1002
1003        quote! {
1004            use ::ff::derive::subtle::ConstantTimeEq;
1005
1006            // By Euler's theorem, if `a` is coprime to `p` (i.e. `gcd(a, p) = 1`), then:
1007            //     a^-1 ≡ a^(phi(p) - 1) mod p
1008            //
1009            // `ff_derive` requires that `p` is prime; in this case, `phi(p) = p - 1`, and
1010            // thus:
1011            //     a^-1 ≡ a^(p - 2) mod p
1012            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        // a.0[0], a.0[1], ..., 0, 0, 0, 0, ...
1027        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    // Since moduli_declare! already implements some traits, we need to conditionally
1070    // compile some of the trait impls depending on whether we're in zkvm or not.
1071    // So, we create a new module with #[cfg(not(target_os = "zkvm"))] and place the impls in there.
1072    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        /// Elements are ordered lexicographically.
1106        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        // All the traits that are implemented in this module are already implemented
1194        // on our zkvm-compatible struct, so we need to conditionally implement them
1195        #[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                    // This cannot exceed the backing capacity.
1266                    self.add_nocarry(other);
1267
1268                    // However, it may need to be reduced.
1269                    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` is larger than `self`, we'll need to add the modulus to self first.
1306                    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                    // Try to subtract the modulus
1389                    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                    // If the element is smaller than MODULUS then the
1394                    // subtraction will underflow, producing a borrow value
1395                    // of 0xffff...ffff. Otherwise, it'll be zero.
1396                    let is_some = ::ff::derive::subtle::Choice::from((borrow as u8) & 1);
1397
1398                    // Convert to Montgomery form by computing
1399                    // (a.R^0 * R^2) / R = a.R
1400                    ::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                    // TODO: This looks like a constant-time result, but r.mont_reduce() is
1444                    // currently implemented using variable-time code.
1445                    ::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            /// Computes a uniformly random element using rejection sampling.
1475            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                        // Mask away the unused most-significant bits.
1492                        // Note: In some edge cases, `REPR_SHAVE_BITS` could be 64, in which case
1493                        // `0xfff... >> REPR_SHAVE_BITS` overflows. So use `checked_shr` instead.
1494                        // This is always sufficient because we will have at most one spare limb
1495                        // to accommodate values of up to twice the modulus.
1496                        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                    // This cannot exceed the backing capacity.
1528                    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                    // However, it may need to be reduced.
1537                    ret.reduce();
1538
1539                    ret
1540                }
1541            }
1542
1543            /// Note that invert is not constant-time in the zkvm.
1544            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            /// Note that sqrt is not constant-time in the zkvm
1580            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            /// Compares two elements in native representation. This is only used
1598            /// internally.
1599            #[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            /// Determines if the element is really in the field. This is only used
1613            /// internally.
1614            #[inline(always)]
1615            #[cfg(not(target_os = "zkvm"))]
1616            fn is_valid(&self) -> bool {
1617                // The Ord impl calls `reduce`, which in turn calls `is_valid`, so we use
1618                // this internal function to eliminate the cycle.
1619                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            /// Subtracts the modulus from this element if this element is not in the
1647            /// field. Only used internally.
1648            #[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                // The Montgomery reduction here is based on Algorithm 14.32 in
1665                // Handbook of Applied Cryptography
1666                // <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
1667
1668                #montgomery_impl
1669
1670                self.reduce();
1671            }
1672
1673            // A variant of IntMod::is_reduced that runs in constant time
1674            #[cfg(target_os = "zkvm")]
1675            fn constant_time_is_reduced(&self) -> ::ff::derive::subtle::Choice {
1676                let mut is_less = 0u8.into();
1677                // Iterate over limbs in little endian order and retain the result of the last non-equal comparison.
1678                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                // If all limbs are equal, is_less is false
1686                is_less
1687            }
1688        }
1689    }
1690}