From 81afd509534e86402eb8a84987b9858e8f2798d0 Mon Sep 17 00:00:00 2001 From: "Alex J. Malozemoff" Date: Tue, 23 Aug 2022 13:50:59 -0700 Subject: [PATCH 1/8] Expose the zero, one, and generator elements as constants --- ff_derive/src/lib.rs | 6 ++++++ src/lib.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/ff_derive/src/lib.rs b/ff_derive/src/lib.rs index abf81de..db17fc5 100644 --- a/ff_derive/src/lib.rs +++ b/ff_derive/src/lib.rs @@ -1211,6 +1211,8 @@ fn prime_field_impl( GENERATOR } + const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; + const S: u32 = S; fn root_of_unity() -> Self { @@ -1250,11 +1252,15 @@ fn prime_field_impl( #name([0; #limbs]) } + const ZERO: Self = #name([0; #limbs]); + #[inline] fn one() -> Self { R } + const ONE: Self = R; + #[inline] fn is_zero(&self) -> ::ff::derive::subtle::Choice { use ::ff::derive::subtle::ConstantTimeEq; diff --git a/src/lib.rs b/src/lib.rs index 4ccd0de..91c3fef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,9 +65,13 @@ pub trait Field: /// Returns the zero element of the field, the additive identity. fn zero() -> Self; + const ZERO: Self; + /// Returns the one element of the field, the multiplicative identity. fn one() -> Self; + const ONE: Self; + /// Returns true iff this element is zero. fn is_zero(&self) -> Choice { self.ct_eq(&Self::zero()) @@ -234,6 +238,8 @@ pub trait PrimeField: Field + From { /// [SageMath]: https://www.sagemath.org/ fn multiplicative_generator() -> Self; + const MULTIPLICATIVE_GENERATOR: Self; + /// An integer `s` satisfying the equation `2^s * t = modulus - 1` with `t` odd. /// /// This is the number of leading zero bits in the little-endian bit representation of From 9de1ab40c341d34d585f5884e0c3ea81994e9898 Mon Sep 17 00:00:00 2001 From: "Alex J. Malozemoff" Date: Wed, 21 Sep 2022 09:41:59 -0700 Subject: [PATCH 2/8] add comments --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 91c3fef..4f92936 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,11 +65,13 @@ pub trait Field: /// Returns the zero element of the field, the additive identity. fn zero() -> Self; + /// The zero element of the field, as a constant. const ZERO: Self; /// Returns the one element of the field, the multiplicative identity. fn one() -> Self; + /// The one element of the field, as a constant. const ONE: Self; /// Returns true iff this element is zero. @@ -238,6 +240,7 @@ pub trait PrimeField: Field + From { /// [SageMath]: https://www.sagemath.org/ fn multiplicative_generator() -> Self; + /// The multiplicative generator, as a constant. const MULTIPLICATIVE_GENERATOR: Self; /// An integer `s` satisfying the equation `2^s * t = modulus - 1` with `t` odd. From b8d8570f67d04cf5a8b82df3d6eb36aeb4732e92 Mon Sep 17 00:00:00 2001 From: Marc Rosen Date: Thu, 20 Oct 2022 15:07:15 -0400 Subject: [PATCH 3/8] Add codegen option instead of derive doesn't cache the output of the proc macro, and using the derive form of this code can cause slowdowns in `cargo check` and `rust-analyzer`. As an alternative, this commit introduces an option to generate the `PrimeField` implementation in a `build.rs` script, to avoid the slowdown. --- Cargo.toml | 7 + README.md | 36 +- ff_codegen/Cargo.toml | 30 + ff_codegen/src/lib.rs | 1269 ++++++++++++++++++++ {ff_derive => ff_codegen}/src/pow_fixed.rs | 0 ff_derive/Cargo.toml | 12 +- ff_derive/src/lib.rs | 1203 +------------------ 7 files changed, 1348 insertions(+), 1209 deletions(-) create mode 100644 ff_codegen/Cargo.toml create mode 100644 ff_codegen/src/lib.rs rename {ff_derive => ff_codegen}/src/pow_fixed.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index b112f6a..d8c299c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,10 @@ +[workspace] +members = [ + ".", + "ff_codegen", + "ff_derive", +] + [package] name = "ff" version = "0.12.0" diff --git a/README.md b/README.md index 6004f6e..fe23035 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,7 @@ ff = { version = "0.12", features = ["derive"] } And then use the macro like so: ```rust -#[macro_use] -extern crate ff; +use ff::PrimeField; #[derive(PrimeField)] #[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"] @@ -50,6 +49,39 @@ struct Fp([u64; 4]); And that's it! `Fp` now implements `Field` and `PrimeField`. +### `build.rs` +Using the `derive(PrimeField)` functionality can slow down compile times. As an alternative, the +`ff` library's code generation functionality can be invoked via a build script. + +First, add the dependencies: +```toml +[dependencies] +ff = { version = "0.12", features = ["derive"] } + +[build-dependencies] +ff_codegen = "0.12" +``` + +Then write the `build.rs` file: +```rust +fn main() { + let path = std::path::Path::new(&std::env::var("OUT_DIR").unwrap()).join("codegen.rs"); + std::fs::write(&path, ff_codegen::PrimeFieldCodegen { + ident: "Fp", + is_pub: false, + modulus: "52435875175126190479447740508185965837690552500527637822603658699938581184513", + generator: "7", + endianness: ff_codegen::ReprEndianness::Little, + }.to_string()).unwrap(); + println!("cargo:rerun-if-changed=build.rs"); +} +``` + +And, finally, in the module you want to include the code in: +```rust +include!(concat!(env!("OUT_DIR"), "/codegen.rs")); +``` + ## Minimum Supported Rust Version Requires Rust **1.56** or higher. diff --git a/ff_codegen/Cargo.toml b/ff_codegen/Cargo.toml new file mode 100644 index 0000000..0f12bf0 --- /dev/null +++ b/ff_codegen/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "ff_codegen" +version = "0.12.0" +authors = [ + "Sean Bowe ", + "Jack Grigg ", +] +description = "Code generator library used to build custom prime field implementations" +documentation = "https://docs.rs/ff-common/" +homepage = "https://github.com/zkcrypto/ff" +license = "MIT/Apache-2.0" +repository = "https://github.com/zkcrypto/ff" +edition = "2021" + +[features] +# enabled when generating bitvec code utilizing the version of ff's bitvec +bits = [] + +[dependencies] +addchain = "0.2" +num-bigint = "0.3" +num-traits = "0.2" +num-integer = "0.1" +proc-macro2 = "1" +quote = "1" +syn = { version = "1", features = ["full"] } +cfg-if = "1" + +[badges] +maintenance = { status = "passively-maintained" } diff --git a/ff_codegen/src/lib.rs b/ff_codegen/src/lib.rs new file mode 100644 index 0000000..52ea99a --- /dev/null +++ b/ff_codegen/src/lib.rs @@ -0,0 +1,1269 @@ +#![recursion_limit = "1024"] + +use num_bigint::BigUint; +use num_integer::Integer; +use num_traits::{One, ToPrimitive, Zero}; +use quote::quote; +use quote::TokenStreamExt; +use std::iter; +use std::str::FromStr; + +mod pow_fixed; + +/// Should finite fields limbs be stored in little endian or big endian order? +/// +/// Note that this decision _only_ affects the order in which digits are stored in the limbs array. +/// It does _not_ cause the bit representation of the underlying `u64` digits to differ from the +/// host architecture's endianness. +#[derive(Clone, Copy, Debug)] +pub enum ReprEndianness { + Big, + Little, +} + +impl FromStr for ReprEndianness { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "big" => Ok(ReprEndianness::Big), + "little" => Ok(ReprEndianness::Little), + _ => Err(()), + } + } +} + +impl ReprEndianness { + fn modulus_repr(&self, modulus: &BigUint, bytes: usize) -> Vec { + match self { + ReprEndianness::Big => { + let buf = modulus.to_bytes_be(); + iter::repeat(0) + .take(bytes - buf.len()) + .chain(buf.into_iter()) + .collect() + } + ReprEndianness::Little => { + let mut buf = modulus.to_bytes_le(); + buf.extend(iter::repeat(0).take(bytes - buf.len())); + buf + } + } + } + + fn from_repr(&self, name: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream { + let read_repr = match self { + ReprEndianness::Big => quote! { + ::ff::derive::byteorder::BigEndian::read_u64_into(r.as_ref(), &mut inner[..]); + inner.reverse(); + }, + ReprEndianness::Little => quote! { + ::ff::derive::byteorder::LittleEndian::read_u64_into(r.as_ref(), &mut inner[..]); + }, + }; + + quote! { + use ::ff::derive::byteorder::ByteOrder; + + let r = { + let mut inner = [0u64; #limbs]; + #read_repr + #name(inner) + }; + } + } + + fn to_repr( + &self, + repr: proc_macro2::TokenStream, + mont_reduce_self_params: &proc_macro2::TokenStream, + limbs: usize, + ) -> proc_macro2::TokenStream { + let bytes = limbs * 8; + + let write_repr = match self { + ReprEndianness::Big => quote! { + r.0.reverse(); + ::ff::derive::byteorder::BigEndian::write_u64_into(&r.0, &mut repr[..]); + }, + ReprEndianness::Little => quote! { + ::ff::derive::byteorder::LittleEndian::write_u64_into(&r.0, &mut repr[..]); + }, + }; + + quote! { + use ::ff::derive::byteorder::ByteOrder; + + let mut r = *self; + r.mont_reduce( + #mont_reduce_self_params + ); + + let mut repr = [0u8; #bytes]; + #write_repr + #repr(repr) + } + } + + fn iter_be(&self) -> proc_macro2::TokenStream { + match self { + ReprEndianness::Big => quote! {self.0.iter()}, + ReprEndianness::Little => quote! {self.0.iter().rev()}, + } + } +} + +// Implement the wrapped ident `repr` with `bytes` bytes. +fn prime_field_repr_impl( + repr: &syn::Ident, + endianness: &ReprEndianness, + bytes: usize, +) -> proc_macro2::TokenStream { + let repr_iter_be = endianness.iter_be(); + + quote! { + #[derive(Copy, Clone)] + pub struct #repr(pub [u8; #bytes]); + + impl ::ff::derive::subtle::ConstantTimeEq for #repr { + fn ct_eq(&self, other: &#repr) -> ::ff::derive::subtle::Choice { + self.0 + .iter() + .zip(other.0.iter()) + .map(|(a, b)| a.ct_eq(b)) + .fold(1.into(), |acc, x| acc & x) + } + } + + impl ::core::cmp::PartialEq for #repr { + fn eq(&self, other: &#repr) -> bool { + use ::ff::derive::subtle::ConstantTimeEq; + self.ct_eq(other).into() + } + } + + impl ::core::cmp::Eq for #repr { } + + impl ::core::default::Default for #repr { + fn default() -> #repr { + #repr([0u8; #bytes]) + } + } + + impl ::core::fmt::Debug for #repr + { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "0x")?; + for i in #repr_iter_be { + write!(f, "{:02x}", *i)?; + } + + Ok(()) + } + } + + impl AsRef<[u8]> for #repr { + #[inline(always)] + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + impl AsMut<[u8]> for #repr { + #[inline(always)] + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } + } + } +} + +/// Convert BigUint into a vector of 64-bit limbs. +fn biguint_to_real_u64_vec(mut v: BigUint, limbs: usize) -> Vec { + let m = BigUint::one() << 64; + let mut ret = vec![]; + + while v > BigUint::zero() { + let limb: BigUint = &v % &m; + ret.push(limb.to_u64().unwrap()); + v >>= 64; + } + + while ret.len() < limbs { + ret.push(0); + } + + assert!(ret.len() == limbs); + + ret +} + +/// Convert BigUint into a tokenized vector of 64-bit limbs. +fn biguint_to_u64_vec(v: BigUint, limbs: usize) -> proc_macro2::TokenStream { + let ret = biguint_to_real_u64_vec(v, limbs); + quote!([#(#ret,)*]) +} + +fn biguint_num_bits(mut v: BigUint) -> u32 { + let mut bits = 0; + + while v != BigUint::zero() { + v >>= 1; + bits += 1; + } + + bits +} + +/// BigUint modular exponentiation by square-and-multiply. +fn exp(base: BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint { + let mut ret = BigUint::one(); + + for i in exp + .to_bytes_be() + .into_iter() + .flat_map(|x| (0..8).rev().map(move |i| (x >> i).is_odd())) + { + ret = (&ret * &ret) % modulus; + if i { + ret = (ret * &base) % modulus; + } + } + + ret +} + +#[test] +fn test_exp() { + assert_eq!( + exp( + BigUint::from_str("4398572349857239485729348572983472345").unwrap(), + &BigUint::from_str("5489673498567349856734895").unwrap(), + &BigUint::from_str( + "52435875175126190479447740508185965837690552500527637822603658699938581184513" + ) + .unwrap() + ), + BigUint::from_str( + "4371221214068404307866768905142520595925044802278091865033317963560480051536" + ) + .unwrap() + ); +} + +fn prime_field_constants_and_sqrt( + name: &syn::Ident, + modulus: &BigUint, + limbs: usize, + generator: &BigUint, +) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { + let bytes = limbs * 8; + let modulus_num_bits = biguint_num_bits(modulus.clone()); + + // The number of bits we should "shave" from a randomly sampled reputation, i.e., + // if our modulus is 381 bits and our representation is 384 bits, we should shave + // 3 bits from the beginning of a randomly sampled 384 bit representation to + // reduce the cost of rejection sampling. + let repr_shave_bits = (64 * limbs as u32) - biguint_num_bits(modulus.clone()); + + // Compute R = 2**(64 * limbs) mod m + let r = (BigUint::one() << (limbs * 64)) % modulus; + + // modulus - 1 = 2^s * t + let mut s: u32 = 0; + let mut t = modulus - BigUint::from_str("1").unwrap(); + while t.is_even() { + t >>= 1; + s += 1; + } + + // Compute 2^s root of unity given the generator + let root_of_unity = + biguint_to_u64_vec((exp(generator.clone(), &t, &modulus) * &r) % modulus, limbs); + let generator = biguint_to_u64_vec((generator.clone() * &r) % modulus, limbs); + + let sqrt_impl = + if (modulus % BigUint::from_str("4").unwrap()) == BigUint::from_str("3").unwrap() { + // Addition chain for (r + 1) // 4 + let mod_plus_1_over_4 = pow_fixed::generate( + "e! {self}, + (modulus + BigUint::from_str("1").unwrap()) >> 2, + ); + + quote! { + use ::ff::derive::subtle::ConstantTimeEq; + + // Because r = 3 (mod 4) + // sqrt can be done with only one exponentiation, + // via the computation of self^((r + 1) // 4) (mod r) + let sqrt = { + #mod_plus_1_over_4 + }; + + ::ff::derive::subtle::CtOption::new( + sqrt, + (sqrt * &sqrt).ct_eq(self), // Only return Some if it's the square root. + ) + } + } else if (modulus % BigUint::from_str("16").unwrap()) == BigUint::from_str("1").unwrap() { + // Addition chain for (t - 1) // 2 + let t_minus_1_over_2 = if t == BigUint::one() { + quote!( #name::one() ) + } else { + pow_fixed::generate("e! {self}, (&t - BigUint::one()) >> 1) + }; + + quote! { + // Tonelli-Shank's algorithm for q mod 16 = 1 + // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) + use ::ff::derive::subtle::{ConditionallySelectable, ConstantTimeEq}; + + // w = self^((t - 1) // 2) + let w = { + #t_minus_1_over_2 + }; + + let mut v = S; + let mut x = *self * &w; + let mut b = x * &w; + + // Initialize z as the 2^S root of unity. + let mut z = ROOT_OF_UNITY; + + for max_v in (1..=S).rev() { + let mut k = 1; + let mut tmp = b.square(); + let mut j_less_than_v: ::ff::derive::subtle::Choice = 1.into(); + + for j in 2..max_v { + let tmp_is_one = tmp.ct_eq(&#name::one()); + let squared = #name::conditional_select(&tmp, &z, tmp_is_one).square(); + tmp = #name::conditional_select(&squared, &tmp, tmp_is_one); + let new_z = #name::conditional_select(&z, &squared, tmp_is_one); + j_less_than_v &= !j.ct_eq(&v); + k = u32::conditional_select(&j, &k, tmp_is_one); + z = #name::conditional_select(&z, &new_z, j_less_than_v); + } + + let result = x * &z; + x = #name::conditional_select(&result, &x, b.ct_eq(&#name::one())); + z = z.square(); + b *= &z; + v = k; + } + + ::ff::derive::subtle::CtOption::new( + x, + (x * &x).ct_eq(self), // Only return Some if it's the square root. + ) + } + } else { + syn::Error::new_spanned( + &name, + "ff_derive can't generate a square root function for this field.", + ) + .to_compile_error() + }; + + // Compute R^2 mod m + let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs); + + let r = biguint_to_u64_vec(r, limbs); + let modulus_le_bytes = ReprEndianness::Little.modulus_repr(modulus, limbs * 8); + let modulus = biguint_to_real_u64_vec(modulus.clone(), limbs); + + // Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1 + let mut inv = 1u64; + for _ in 0..63 { + inv = inv.wrapping_mul(inv); + inv = inv.wrapping_mul(modulus[0]); + } + inv = inv.wrapping_neg(); + + ( + quote! { + type REPR_BYTES = [u8; #bytes]; + type REPR_BITS = REPR_BYTES; + + /// This is the modulus m of the prime field + const MODULUS: REPR_BITS = [#(#modulus_le_bytes,)*]; + + /// This is the modulus m of the prime field in limb form + const MODULUS_LIMBS: #name = #name([#(#modulus,)*]); + + /// The number of bits needed to represent the modulus. + const MODULUS_BITS: u32 = #modulus_num_bits; + + /// The number of bits that must be shaved from the beginning of + /// the representation when randomly sampling. + const REPR_SHAVE_BITS: u32 = #repr_shave_bits; + + /// 2^{limbs*64} mod m + const R: #name = #name(#r); + + /// 2^{limbs*64*2} mod m + const R2: #name = #name(#r2); + + /// -(m^{-1} mod m) mod m + const INV: u64 = #inv; + + /// Multiplicative generator of `MODULUS` - 1 order, also quadratic + /// nonresidue. + const GENERATOR: #name = #name(#generator); + + /// 2^s * t = MODULUS - 1 with t odd + const S: u32 = #s; + + /// 2^s root of unity computed by GENERATOR^t + const ROOT_OF_UNITY: #name = #name(#root_of_unity); + }, + sqrt_impl, + ) +} + +/// Implement PrimeField for the derived type. +fn prime_field_impl( + name: &syn::Ident, + repr: &syn::Ident, + modulus: &BigUint, + endianness: &ReprEndianness, + limbs: usize, + sqrt_impl: proc_macro2::TokenStream, +) -> proc_macro2::TokenStream { + // Returns r{n} as an ident. + fn get_temp(n: usize) -> syn::Ident { + syn::Ident::new(&format!("r{}", n), proc_macro2::Span::call_site()) + } + + // The parameter list for the mont_reduce() internal method. + // r0: u64, mut r1: u64, mut r2: u64, ... + let mut mont_paramlist = proc_macro2::TokenStream::new(); + mont_paramlist.append_separated( + (0..(limbs * 2)).map(|i| (i, get_temp(i))).map(|(i, x)| { + if i != 0 { + quote! {mut #x: u64} + } else { + quote! {#x: u64} + } + }), + proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), + ); + + // Implement montgomery reduction for some number of limbs + fn mont_impl(limbs: usize) -> proc_macro2::TokenStream { + let mut gen = proc_macro2::TokenStream::new(); + + for i in 0..limbs { + { + let temp = get_temp(i); + gen.extend(quote! { + let k = #temp.wrapping_mul(INV); + let (_, carry) = ::ff::derive::mac(#temp, k, MODULUS_LIMBS.0[0], 0); + }); + } + + for j in 1..limbs { + let temp = get_temp(i + j); + gen.extend(quote! { + let (#temp, carry) = ::ff::derive::mac(#temp, k, MODULUS_LIMBS.0[#j], carry); + }); + } + + let temp = get_temp(i + limbs); + + if i == 0 { + gen.extend(quote! { + let (#temp, carry2) = ::ff::derive::adc(#temp, 0, carry); + }); + } else { + gen.extend(quote! { + let (#temp, carry2) = ::ff::derive::adc(#temp, carry2, carry); + }); + } + } + + for i in 0..limbs { + let temp = get_temp(limbs + i); + + gen.extend(quote! { + self.0[#i] = #temp; + }); + } + + gen + } + + fn sqr_impl(a: proc_macro2::TokenStream, limbs: usize) -> proc_macro2::TokenStream { + let mut gen = proc_macro2::TokenStream::new(); + + if limbs > 1 { + for i in 0..(limbs - 1) { + gen.extend(quote! { + let carry = 0; + }); + + for j in (i + 1)..limbs { + let temp = get_temp(i + j); + if i == 0 { + gen.extend(quote! { + let (#temp, carry) = ::ff::derive::mac(0, #a.0[#i], #a.0[#j], carry); + }); + } else { + gen.extend(quote! { + let (#temp, carry) = ::ff::derive::mac(#temp, #a.0[#i], #a.0[#j], carry); + }); + } + } + + let temp = get_temp(i + limbs); + + gen.extend(quote! { + let #temp = carry; + }); + } + + for i in 1..(limbs * 2) { + let temp0 = get_temp(limbs * 2 - i); + let temp1 = get_temp(limbs * 2 - i - 1); + + if i == 1 { + gen.extend(quote! { + let #temp0 = #temp1 >> 63; + }); + } else if i == (limbs * 2 - 1) { + gen.extend(quote! { + let #temp0 = #temp0 << 1; + }); + } else { + gen.extend(quote! { + let #temp0 = (#temp0 << 1) | (#temp1 >> 63); + }); + } + } + } else { + let temp1 = get_temp(1); + gen.extend(quote! { + let #temp1 = 0; + }); + } + + for i in 0..limbs { + let temp0 = get_temp(i * 2); + let temp1 = get_temp(i * 2 + 1); + if i == 0 { + gen.extend(quote! { + let (#temp0, carry) = ::ff::derive::mac(0, #a.0[#i], #a.0[#i], 0); + }); + } else { + gen.extend(quote! { + let (#temp0, carry) = ::ff::derive::mac(#temp0, #a.0[#i], #a.0[#i], carry); + }); + } + + gen.extend(quote! { + let (#temp1, carry) = ::ff::derive::adc(#temp1, 0, carry); + }); + } + + let mut mont_calling = proc_macro2::TokenStream::new(); + mont_calling.append_separated( + (0..(limbs * 2)).map(get_temp), + proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), + ); + + gen.extend(quote! { + let mut ret = *self; + ret.mont_reduce(#mont_calling); + ret + }); + + gen + } + + fn mul_impl( + a: proc_macro2::TokenStream, + b: proc_macro2::TokenStream, + limbs: usize, + ) -> proc_macro2::TokenStream { + let mut gen = proc_macro2::TokenStream::new(); + + for i in 0..limbs { + gen.extend(quote! { + let carry = 0; + }); + + for j in 0..limbs { + let temp = get_temp(i + j); + + if i == 0 { + gen.extend(quote! { + let (#temp, carry) = ::ff::derive::mac(0, #a.0[#i], #b.0[#j], carry); + }); + } else { + gen.extend(quote! { + let (#temp, carry) = ::ff::derive::mac(#temp, #a.0[#i], #b.0[#j], carry); + }); + } + } + + let temp = get_temp(i + limbs); + + gen.extend(quote! { + let #temp = carry; + }); + } + + let mut mont_calling = proc_macro2::TokenStream::new(); + mont_calling.append_separated( + (0..(limbs * 2)).map(get_temp), + proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), + ); + + gen.extend(quote! { + self.mont_reduce(#mont_calling); + }); + + gen + } + + /// Generates an implementation of multiplicative inversion within the target prime + /// field. + fn inv_impl( + a: proc_macro2::TokenStream, + name: &syn::Ident, + modulus: &BigUint, + ) -> proc_macro2::TokenStream { + // Addition chain for p - 2 + let mod_minus_2 = pow_fixed::generate(&a, modulus - BigUint::from(2u64)); + + quote! { + use ::ff::derive::subtle::ConstantTimeEq; + + // By Euler's theorem, if `a` is coprime to `p` (i.e. `gcd(a, p) = 1`), then: + // a^-1 ≡ a^(phi(p) - 1) mod p + // + // `ff_derive` requires that `p` is prime; in this case, `phi(p) = p - 1`, and + // thus: + // a^-1 ≡ a^(p - 2) mod p + let inv = { + #mod_minus_2 + }; + + ::ff::derive::subtle::CtOption::new(inv, !#a.ct_eq(&#name::zero())) + } + } + + let squaring_impl = sqr_impl(quote! {self}, limbs); + let multiply_impl = mul_impl(quote! {self}, quote! {other}, limbs); + let invert_impl = inv_impl(quote! {self}, name, modulus); + let montgomery_impl = mont_impl(limbs); + + // self.0[0].ct_eq(&other.0[0]) & self.0[1].ct_eq(&other.0[1]) & ... + let mut ct_eq_impl = proc_macro2::TokenStream::new(); + ct_eq_impl.append_separated( + (0..limbs).map(|i| quote! { self.0[#i].ct_eq(&other.0[#i]) }), + proc_macro2::Punct::new('&', proc_macro2::Spacing::Alone), + ); + + fn mont_reduce_params(a: proc_macro2::TokenStream, limbs: usize) -> proc_macro2::TokenStream { + // a.0[0], a.0[1], ..., 0, 0, 0, 0, ... + let mut mont_reduce_params = proc_macro2::TokenStream::new(); + mont_reduce_params.append_separated( + (0..limbs) + .map(|i| quote! { #a.0[#i] }) + .chain((0..limbs).map(|_| quote! {0})), + proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), + ); + mont_reduce_params + } + + let mont_reduce_self_params = mont_reduce_params(quote! {self}, limbs); + let mont_reduce_other_params = mont_reduce_params(quote! {other}, limbs); + + let from_repr_impl = endianness.from_repr(name, limbs); + let to_repr_impl = endianness.to_repr(quote! {#repr}, &mont_reduce_self_params, limbs); + + cfg_if::cfg_if! { + if #[cfg(feature = "bits")] { + let to_le_bits_impl = ReprEndianness::Little.to_repr( + quote! {::ff::derive::bitvec::array::BitArray::new}, + &mont_reduce_self_params, + limbs, + ); + + let prime_field_bits_impl = quote! { + impl ::ff::PrimeFieldBits for #name { + type ReprBits = REPR_BITS; + + fn to_le_bits(&self) -> ::ff::FieldBits { + #to_le_bits_impl + } + + fn char_le_bits() -> ::ff::FieldBits { + ::ff::FieldBits::new(MODULUS) + } + } + }; + } else { + let prime_field_bits_impl = quote! {}; + } + }; + + let top_limb_index = limbs - 1; + + quote! { + impl ::core::marker::Copy for #name { } + + impl ::core::clone::Clone for #name { + fn clone(&self) -> #name { + *self + } + } + + impl ::core::default::Default for #name { + fn default() -> #name { + use ::ff::Field; + #name::zero() + } + } + + impl ::ff::derive::subtle::ConstantTimeEq for #name { + fn ct_eq(&self, other: &#name) -> ::ff::derive::subtle::Choice { + use ::ff::PrimeField; + self.to_repr().ct_eq(&other.to_repr()) + } + } + + impl ::core::cmp::PartialEq for #name { + fn eq(&self, other: &#name) -> bool { + use ::ff::derive::subtle::ConstantTimeEq; + self.ct_eq(other).into() + } + } + + impl ::core::cmp::Eq for #name { } + + impl ::core::fmt::Debug for #name + { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use ::ff::PrimeField; + write!(f, "{}({:?})", stringify!(#name), self.to_repr()) + } + } + + /// Elements are ordered lexicographically. + impl Ord for #name { + #[inline(always)] + fn cmp(&self, other: &#name) -> ::core::cmp::Ordering { + let mut a = *self; + a.mont_reduce( + #mont_reduce_self_params + ); + + let mut b = *other; + b.mont_reduce( + #mont_reduce_other_params + ); + + a.cmp_native(&b) + } + } + + impl PartialOrd for #name { + #[inline(always)] + fn partial_cmp(&self, other: &#name) -> Option<::core::cmp::Ordering> { + Some(self.cmp(other)) + } + } + + impl From for #name { + #[inline(always)] + fn from(val: u64) -> #name { + let mut raw = [0u64; #limbs]; + raw[0] = val; + #name(raw) * R2 + } + } + + impl From<#name> for #repr { + fn from(e: #name) -> #repr { + use ::ff::PrimeField; + e.to_repr() + } + } + + impl<'a> From<&'a #name> for #repr { + fn from(e: &'a #name) -> #repr { + use ::ff::PrimeField; + e.to_repr() + } + } + + impl ::ff::derive::subtle::ConditionallySelectable for #name { + fn conditional_select(a: &#name, b: &#name, choice: ::ff::derive::subtle::Choice) -> #name { + let mut res = [0u64; #limbs]; + for i in 0..#limbs { + res[i] = u64::conditional_select(&a.0[i], &b.0[i], choice); + } + #name(res) + } + } + + impl ::core::ops::Neg for #name { + type Output = #name; + + #[inline] + fn neg(self) -> #name { + use ::ff::Field; + + let mut ret = self; + if !ret.is_zero_vartime() { + let mut tmp = MODULUS_LIMBS; + tmp.sub_noborrow(&ret); + ret = tmp; + } + ret + } + } + + impl<'r> ::core::ops::Add<&'r #name> for #name { + type Output = #name; + + #[inline] + fn add(self, other: &#name) -> #name { + use ::core::ops::AddAssign; + + let mut ret = self; + ret.add_assign(other); + ret + } + } + + impl ::core::ops::Add for #name { + type Output = #name; + + #[inline] + fn add(self, other: #name) -> Self { + self + &other + } + } + + impl<'r> ::core::ops::AddAssign<&'r #name> for #name { + #[inline] + fn add_assign(&mut self, other: &#name) { + // This cannot exceed the backing capacity. + self.add_nocarry(other); + + // However, it may need to be reduced. + self.reduce(); + } + } + + impl ::core::ops::AddAssign for #name { + #[inline] + fn add_assign(&mut self, other: #name) { + self.add_assign(&other); + } + } + + impl<'r> ::core::ops::Sub<&'r #name> for #name { + type Output = #name; + + #[inline] + fn sub(self, other: &#name) -> Self { + use ::core::ops::SubAssign; + + let mut ret = self; + ret.sub_assign(other); + ret + } + } + + impl ::core::ops::Sub for #name { + type Output = #name; + + #[inline] + fn sub(self, other: #name) -> Self { + self - &other + } + } + + impl<'r> ::core::ops::SubAssign<&'r #name> for #name { + #[inline] + fn sub_assign(&mut self, other: &#name) { + // If `other` is larger than `self`, we'll need to add the modulus to self first. + if other.cmp_native(self) == ::core::cmp::Ordering::Greater { + self.add_nocarry(&MODULUS_LIMBS); + } + + self.sub_noborrow(other); + } + } + + impl ::core::ops::SubAssign for #name { + #[inline] + fn sub_assign(&mut self, other: #name) { + self.sub_assign(&other); + } + } + + impl<'r> ::core::ops::Mul<&'r #name> for #name { + type Output = #name; + + #[inline] + fn mul(self, other: &#name) -> Self { + use ::core::ops::MulAssign; + + let mut ret = self; + ret.mul_assign(other); + ret + } + } + + impl ::core::ops::Mul for #name { + type Output = #name; + + #[inline] + fn mul(self, other: #name) -> Self { + self * &other + } + } + + impl<'r> ::core::ops::MulAssign<&'r #name> for #name { + #[inline] + fn mul_assign(&mut self, other: &#name) + { + #multiply_impl + } + } + + impl ::core::ops::MulAssign for #name { + #[inline] + fn mul_assign(&mut self, other: #name) + { + self.mul_assign(&other); + } + } + + impl ::ff::PrimeField for #name { + type Repr = #repr; + + fn from_repr(r: #repr) -> ::ff::derive::subtle::CtOption<#name> { + #from_repr_impl + + // Try to subtract the modulus + let borrow = r.0.iter().zip(MODULUS_LIMBS.0.iter()).fold(0, |borrow, (a, b)| { + ::ff::derive::sbb(*a, *b, borrow).1 + }); + + // If the element is smaller than MODULUS then the + // subtraction will underflow, producing a borrow value + // of 0xffff...ffff. Otherwise, it'll be zero. + let is_some = ::ff::derive::subtle::Choice::from((borrow as u8) & 1); + + // Convert to Montgomery form by computing + // (a.R^0 * R^2) / R = a.R + ::ff::derive::subtle::CtOption::new(r * &R2, is_some) + } + + fn from_repr_vartime(r: #repr) -> Option<#name> { + #from_repr_impl + + if r.is_valid() { + Some(r * R2) + } else { + None + } + } + + fn to_repr(&self) -> #repr { + #to_repr_impl + } + + #[inline(always)] + fn is_odd(&self) -> ::ff::derive::subtle::Choice { + let mut r = *self; + r.mont_reduce( + #mont_reduce_self_params + ); + + // TODO: This looks like a constant-time result, but r.mont_reduce() is + // currently implemented using variable-time code. + ::ff::derive::subtle::Choice::from((r.0[0] & 1) as u8) + } + + const NUM_BITS: u32 = MODULUS_BITS; + + const CAPACITY: u32 = Self::NUM_BITS - 1; + + fn multiplicative_generator() -> Self { + GENERATOR + } + + const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; + + const S: u32 = S; + + fn root_of_unity() -> Self { + ROOT_OF_UNITY + } + } + + #prime_field_bits_impl + + impl ::ff::Field for #name { + /// Computes a uniformly random element using rejection sampling. + fn random(mut rng: impl ::ff::derive::rand_core::RngCore) -> Self { + loop { + let mut tmp = { + let mut repr = [0u64; #limbs]; + for i in 0..#limbs { + repr[i] = rng.next_u64(); + } + #name(repr) + }; + + // Mask away the unused most-significant bits. + // Note: In some edge cases, `REPR_SHAVE_BITS` could be 64, in which case + // `0xfff... >> REPR_SHAVE_BITS` overflows. So use `checked_shr` instead. + // This is always sufficient because we will have at most one spare limb + // to accommodate values of up to twice the modulus. + tmp.0.as_mut()[#top_limb_index] &= 0xffffffffffffffffu64.checked_shr(REPR_SHAVE_BITS).unwrap_or(0); + + if tmp.is_valid() { + return tmp + } + } + } + + #[inline] + fn zero() -> Self { + #name([0; #limbs]) + } + + const ZERO: Self = #name([0; #limbs]); + + #[inline] + fn one() -> Self { + R + } + + const ONE: Self = R; + + #[inline] + fn is_zero(&self) -> ::ff::derive::subtle::Choice { + use ::ff::derive::subtle::ConstantTimeEq; + self.ct_eq(&Self::zero()) + } + + #[inline] + fn is_zero_vartime(&self) -> bool { + self.0.iter().all(|&e| e == 0) + } + + #[inline] + fn double(&self) -> Self { + let mut ret = *self; + + // This cannot exceed the backing capacity. + let mut last = 0; + for i in &mut ret.0 { + let tmp = *i >> 63; + *i <<= 1; + *i |= last; + last = tmp; + } + + // However, it may need to be reduced. + ret.reduce(); + + ret + } + + fn invert(&self) -> ::ff::derive::subtle::CtOption { + #invert_impl + } + + #[inline] + fn square(&self) -> Self + { + #squaring_impl + } + + fn sqrt(&self) -> ::ff::derive::subtle::CtOption { + #sqrt_impl + } + } + + impl #name { + /// Compares two elements in native representation. This is only used + /// internally. + #[inline(always)] + fn cmp_native(&self, other: &#name) -> ::core::cmp::Ordering { + for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { + if a < b { + return ::core::cmp::Ordering::Less + } else if a > b { + return ::core::cmp::Ordering::Greater + } + } + + ::core::cmp::Ordering::Equal + } + + /// Determines if the element is really in the field. This is only used + /// internally. + #[inline(always)] + fn is_valid(&self) -> bool { + // The Ord impl calls `reduce`, which in turn calls `is_valid`, so we use + // this internal function to eliminate the cycle. + self.cmp_native(&MODULUS_LIMBS) == ::core::cmp::Ordering::Less + } + + #[inline(always)] + fn add_nocarry(&mut self, other: &#name) { + let mut carry = 0; + + for (a, b) in self.0.iter_mut().zip(other.0.iter()) { + let (new_a, new_carry) = ::ff::derive::adc(*a, *b, carry); + *a = new_a; + carry = new_carry; + } + } + + #[inline(always)] + fn sub_noborrow(&mut self, other: &#name) { + let mut borrow = 0; + + for (a, b) in self.0.iter_mut().zip(other.0.iter()) { + let (new_a, new_borrow) = ::ff::derive::sbb(*a, *b, borrow); + *a = new_a; + borrow = new_borrow; + } + } + + /// Subtracts the modulus from this element if this element is not in the + /// field. Only used interally. + #[inline(always)] + fn reduce(&mut self) { + if !self.is_valid() { + self.sub_noborrow(&MODULUS_LIMBS); + } + } + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + fn mont_reduce( + &mut self, + #mont_paramlist + ) + { + // The Montgomery reduction here is based on Algorithm 14.32 in + // Handbook of Applied Cryptography + // . + + #montgomery_impl + + self.reduce(); + } + } + } +} + +/// The arithmetic in this library only works if the modulus*2 is smaller than the backing +/// representation. Compute the number of limbs we need. +pub fn num_u64_limbs_needed(modulus: &BigUint) -> usize { + let mut limbs = 1; + { + let mod2 = modulus << 1; // modulus * 2 + let mut cur = BigUint::one() << 64; // always 64-bit limbs for now + while cur < mod2 { + limbs += 1; + cur <<= 64; + } + } + limbs +} + +/// Generate the impls needed for a `#[derive(PrimeField)]` invocation. +pub fn prime_field_impls( + ident: &syn::Ident, + modulus: &BigUint, + generator: &BigUint, + endianness: ReprEndianness, +) -> proc_macro2::TokenStream { + // Generate the identifier for the "Repr" type we must construct. + let repr_ident = syn::Ident::new(&format!("{}Repr", ident), proc_macro2::Span::call_site()); + let limbs = num_u64_limbs_needed(modulus); + + let mut gen = proc_macro2::TokenStream::new(); + let (constants_impl, sqrt_impl) = + prime_field_constants_and_sqrt(ident, modulus, limbs, generator); + + gen.extend(constants_impl); + gen.extend(prime_field_repr_impl(&repr_ident, &endianness, limbs * 8)); + gen.extend(prime_field_impl( + ident, + &repr_ident, + modulus, + &endianness, + limbs, + sqrt_impl, + )); + gen +} + +/// Options to configure code generation of a prime field struct. +/// +/// Unlike [`prime_field_impls`], `PrimeFieldCodegen` generates the code for _both_ the struct +/// definition, as well as the required impls. +/// +/// It should be used like so: +/// ```rust +/// println!("{}", ff_codegen::PrimeFieldCodegen { +/// ident: "Fp", +/// is_pub: false, +/// modulus: "52435875175126190479447740508185965837690552500527637822603658699938581184513", +/// generator: "7", +/// endianness: ff_codegen::ReprEndianness::Little, +/// }); +/// ``` +/// See the README for a more complete example. +pub struct PrimeFieldCodegen<'a> { + /// The name of the struct to generate + pub ident: &'a str, + /// If `true`, then the generated struct will be marked as `pub`. + pub is_pub: bool, + /// The modulus of the field, written as a decimal string + pub modulus: &'a str, + /// A generator of the field, written as a decimal string + pub generator: &'a str, + pub endianness: ReprEndianness, +} +impl std::fmt::Display for PrimeFieldCodegen<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let ident = syn::Ident::new(&self.ident, proc_macro2::Span::call_site()); + let modulus = BigUint::from_str(self.modulus).unwrap(); + let generator = BigUint::from_str(self.generator).unwrap(); + let limbs = num_u64_limbs_needed(&modulus); + let mut gen = proc_macro2::TokenStream::new(); + if self.is_pub { + gen.extend(quote! { + #[repr(transparent)] + pub struct #ident([u64; #limbs]); + }); + } else { + gen.extend(quote! { + #[repr(transparent)] + struct #ident([u64; #limbs]); + }); + } + gen.extend(prime_field_impls( + &ident, + &modulus, + &generator, + self.endianness, + )); + write!(f, "{}", gen) + } +} diff --git a/ff_derive/src/pow_fixed.rs b/ff_codegen/src/pow_fixed.rs similarity index 100% rename from ff_derive/src/pow_fixed.rs rename to ff_codegen/src/pow_fixed.rs diff --git a/ff_derive/Cargo.toml b/ff_derive/Cargo.toml index bbe40a1..ca87929 100644 --- a/ff_derive/Cargo.toml +++ b/ff_derive/Cargo.toml @@ -2,8 +2,8 @@ name = "ff_derive" version = "0.12.0" authors = [ - "Sean Bowe ", - "Jack Grigg ", + "Sean Bowe ", + "Jack Grigg ", ] description = "Procedural macro library used to build custom prime field implementations" documentation = "https://docs.rs/ff-derive/" @@ -14,20 +14,16 @@ edition = "2021" [features] # enabled when generating bitvec code utilizing the version of ff's bitvec -bits = [] +bits = ["ff_codegen/bits"] [lib] proc-macro = true [dependencies] -addchain = "0.2" num-bigint = "0.3" -num-traits = "0.2" -num-integer = "0.1" proc-macro2 = "1" -quote = "1" syn = { version = "1", features = ["full"] } -cfg-if = "1" +ff_codegen = { path = "../ff_codegen" } [badges] maintenance = { status = "passively-maintained" } diff --git a/ff_derive/src/lib.rs b/ff_derive/src/lib.rs index db17fc5..9bec284 100644 --- a/ff_derive/src/lib.rs +++ b/ff_derive/src/lib.rs @@ -1,114 +1,8 @@ #![recursion_limit = "1024"] extern crate proc_macro; -extern crate proc_macro2; use num_bigint::BigUint; -use num_integer::Integer; -use num_traits::{One, ToPrimitive, Zero}; -use quote::quote; -use quote::TokenStreamExt; -use std::iter; -use std::str::FromStr; - -mod pow_fixed; - -enum ReprEndianness { - Big, - Little, -} - -impl FromStr for ReprEndianness { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "big" => Ok(ReprEndianness::Big), - "little" => Ok(ReprEndianness::Little), - _ => Err(()), - } - } -} - -impl ReprEndianness { - fn modulus_repr(&self, modulus: &BigUint, bytes: usize) -> Vec { - match self { - ReprEndianness::Big => { - let buf = modulus.to_bytes_be(); - iter::repeat(0) - .take(bytes - buf.len()) - .chain(buf.into_iter()) - .collect() - } - ReprEndianness::Little => { - let mut buf = modulus.to_bytes_le(); - buf.extend(iter::repeat(0).take(bytes - buf.len())); - buf - } - } - } - - fn from_repr(&self, name: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream { - let read_repr = match self { - ReprEndianness::Big => quote! { - ::ff::derive::byteorder::BigEndian::read_u64_into(r.as_ref(), &mut inner[..]); - inner.reverse(); - }, - ReprEndianness::Little => quote! { - ::ff::derive::byteorder::LittleEndian::read_u64_into(r.as_ref(), &mut inner[..]); - }, - }; - - quote! { - use ::ff::derive::byteorder::ByteOrder; - - let r = { - let mut inner = [0u64; #limbs]; - #read_repr - #name(inner) - }; - } - } - - fn to_repr( - &self, - repr: proc_macro2::TokenStream, - mont_reduce_self_params: &proc_macro2::TokenStream, - limbs: usize, - ) -> proc_macro2::TokenStream { - let bytes = limbs * 8; - - let write_repr = match self { - ReprEndianness::Big => quote! { - r.0.reverse(); - ::ff::derive::byteorder::BigEndian::write_u64_into(&r.0, &mut repr[..]); - }, - ReprEndianness::Little => quote! { - ::ff::derive::byteorder::LittleEndian::write_u64_into(&r.0, &mut repr[..]); - }, - }; - - quote! { - use ::ff::derive::byteorder::ByteOrder; - - let mut r = *self; - r.mont_reduce( - #mont_reduce_self_params - ); - - let mut repr = [0u8; #bytes]; - #write_repr - #repr(repr) - } - } - - fn iter_be(&self) -> proc_macro2::TokenStream { - match self { - ReprEndianness::Big => quote! {self.0.iter()}, - ReprEndianness::Little => quote! {self.0.iter().rev()}, - } - } -} /// Derive the `PrimeField` trait. #[proc_macro_derive( @@ -139,47 +33,15 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { .parse() .expect("PrimeFieldReprEndianness should be 'big' or 'little'"); - // The arithmetic in this library only works if the modulus*2 is smaller than the backing - // representation. Compute the number of limbs we need. - let mut limbs = 1; - { - let mod2 = (&modulus) << 1; // modulus * 2 - let mut cur = BigUint::one() << 64; // always 64-bit limbs for now - while cur < mod2 { - limbs += 1; - cur <<= 64; - } - } + let limbs = ff_codegen::num_u64_limbs_needed(&modulus); // The struct we're deriving for must be a wrapper around `pub [u64; limbs]`. if let Some(err) = validate_struct(&ast, limbs) { return err.into(); } - // Generate the identifier for the "Repr" type we must construct. - let repr_ident = syn::Ident::new( - &format!("{}Repr", ast.ident), - proc_macro2::Span::call_site(), - ); - - let mut gen = proc_macro2::TokenStream::new(); - - let (constants_impl, sqrt_impl) = - prime_field_constants_and_sqrt(&ast.ident, &modulus, limbs, generator); - - gen.extend(constants_impl); - gen.extend(prime_field_repr_impl(&repr_ident, &endianness, limbs * 8)); - gen.extend(prime_field_impl( - &ast.ident, - &repr_ident, - &modulus, - &endianness, - limbs, - sqrt_impl, - )); - // Return the generated impl - gen.into() + ff_codegen::prime_field_impls(&ast.ident, &modulus, &generator, endianness).into() } /// Checks that `body` contains `pub [u64; limbs]`. @@ -257,8 +119,8 @@ fn validate_struct(ast: &syn::DeriveInput, limbs: usize) -> Option match &*expr_group.expr { syn::Expr::Lit(expr_lit) => Some(&expr_lit.lit), _ => None, - } - _ => None + }, + _ => None, }; let lit_int = match match expr_lit { Some(syn::Lit::Int(lit_int)) => Some(lit_int), @@ -323,1060 +185,3 @@ fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option { None } - -// Implement the wrapped ident `repr` with `bytes` bytes. -fn prime_field_repr_impl( - repr: &syn::Ident, - endianness: &ReprEndianness, - bytes: usize, -) -> proc_macro2::TokenStream { - let repr_iter_be = endianness.iter_be(); - - quote! { - #[derive(Copy, Clone)] - pub struct #repr(pub [u8; #bytes]); - - impl ::ff::derive::subtle::ConstantTimeEq for #repr { - fn ct_eq(&self, other: &#repr) -> ::ff::derive::subtle::Choice { - self.0 - .iter() - .zip(other.0.iter()) - .map(|(a, b)| a.ct_eq(b)) - .fold(1.into(), |acc, x| acc & x) - } - } - - impl ::core::cmp::PartialEq for #repr { - fn eq(&self, other: &#repr) -> bool { - use ::ff::derive::subtle::ConstantTimeEq; - self.ct_eq(other).into() - } - } - - impl ::core::cmp::Eq for #repr { } - - impl ::core::default::Default for #repr { - fn default() -> #repr { - #repr([0u8; #bytes]) - } - } - - impl ::core::fmt::Debug for #repr - { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "0x")?; - for i in #repr_iter_be { - write!(f, "{:02x}", *i)?; - } - - Ok(()) - } - } - - impl AsRef<[u8]> for #repr { - #[inline(always)] - fn as_ref(&self) -> &[u8] { - &self.0 - } - } - - impl AsMut<[u8]> for #repr { - #[inline(always)] - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } - } - } -} - -/// Convert BigUint into a vector of 64-bit limbs. -fn biguint_to_real_u64_vec(mut v: BigUint, limbs: usize) -> Vec { - let m = BigUint::one() << 64; - let mut ret = vec![]; - - while v > BigUint::zero() { - let limb: BigUint = &v % &m; - ret.push(limb.to_u64().unwrap()); - v >>= 64; - } - - while ret.len() < limbs { - ret.push(0); - } - - assert!(ret.len() == limbs); - - ret -} - -/// Convert BigUint into a tokenized vector of 64-bit limbs. -fn biguint_to_u64_vec(v: BigUint, limbs: usize) -> proc_macro2::TokenStream { - let ret = biguint_to_real_u64_vec(v, limbs); - quote!([#(#ret,)*]) -} - -fn biguint_num_bits(mut v: BigUint) -> u32 { - let mut bits = 0; - - while v != BigUint::zero() { - v >>= 1; - bits += 1; - } - - bits -} - -/// BigUint modular exponentiation by square-and-multiply. -fn exp(base: BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint { - let mut ret = BigUint::one(); - - for i in exp - .to_bytes_be() - .into_iter() - .flat_map(|x| (0..8).rev().map(move |i| (x >> i).is_odd())) - { - ret = (&ret * &ret) % modulus; - if i { - ret = (ret * &base) % modulus; - } - } - - ret -} - -#[test] -fn test_exp() { - assert_eq!( - exp( - BigUint::from_str("4398572349857239485729348572983472345").unwrap(), - &BigUint::from_str("5489673498567349856734895").unwrap(), - &BigUint::from_str( - "52435875175126190479447740508185965837690552500527637822603658699938581184513" - ) - .unwrap() - ), - BigUint::from_str( - "4371221214068404307866768905142520595925044802278091865033317963560480051536" - ) - .unwrap() - ); -} - -fn prime_field_constants_and_sqrt( - name: &syn::Ident, - modulus: &BigUint, - limbs: usize, - generator: BigUint, -) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { - let bytes = limbs * 8; - let modulus_num_bits = biguint_num_bits(modulus.clone()); - - // The number of bits we should "shave" from a randomly sampled reputation, i.e., - // if our modulus is 381 bits and our representation is 384 bits, we should shave - // 3 bits from the beginning of a randomly sampled 384 bit representation to - // reduce the cost of rejection sampling. - let repr_shave_bits = (64 * limbs as u32) - biguint_num_bits(modulus.clone()); - - // Compute R = 2**(64 * limbs) mod m - let r = (BigUint::one() << (limbs * 64)) % modulus; - - // modulus - 1 = 2^s * t - let mut s: u32 = 0; - let mut t = modulus - BigUint::from_str("1").unwrap(); - while t.is_even() { - t >>= 1; - s += 1; - } - - // Compute 2^s root of unity given the generator - let root_of_unity = - biguint_to_u64_vec((exp(generator.clone(), &t, &modulus) * &r) % modulus, limbs); - let generator = biguint_to_u64_vec((generator.clone() * &r) % modulus, limbs); - - let sqrt_impl = - if (modulus % BigUint::from_str("4").unwrap()) == BigUint::from_str("3").unwrap() { - // Addition chain for (r + 1) // 4 - let mod_plus_1_over_4 = pow_fixed::generate( - "e! {self}, - (modulus + BigUint::from_str("1").unwrap()) >> 2, - ); - - quote! { - use ::ff::derive::subtle::ConstantTimeEq; - - // Because r = 3 (mod 4) - // sqrt can be done with only one exponentiation, - // via the computation of self^((r + 1) // 4) (mod r) - let sqrt = { - #mod_plus_1_over_4 - }; - - ::ff::derive::subtle::CtOption::new( - sqrt, - (sqrt * &sqrt).ct_eq(self), // Only return Some if it's the square root. - ) - } - } else if (modulus % BigUint::from_str("16").unwrap()) == BigUint::from_str("1").unwrap() { - // Addition chain for (t - 1) // 2 - let t_minus_1_over_2 = if t == BigUint::one() { - quote!( #name::one() ) - } else { - pow_fixed::generate("e! {self}, (&t - BigUint::one()) >> 1) - }; - - quote! { - // Tonelli-Shank's algorithm for q mod 16 = 1 - // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) - use ::ff::derive::subtle::{ConditionallySelectable, ConstantTimeEq}; - - // w = self^((t - 1) // 2) - let w = { - #t_minus_1_over_2 - }; - - let mut v = S; - let mut x = *self * &w; - let mut b = x * &w; - - // Initialize z as the 2^S root of unity. - let mut z = ROOT_OF_UNITY; - - for max_v in (1..=S).rev() { - let mut k = 1; - let mut tmp = b.square(); - let mut j_less_than_v: ::ff::derive::subtle::Choice = 1.into(); - - for j in 2..max_v { - let tmp_is_one = tmp.ct_eq(&#name::one()); - let squared = #name::conditional_select(&tmp, &z, tmp_is_one).square(); - tmp = #name::conditional_select(&squared, &tmp, tmp_is_one); - let new_z = #name::conditional_select(&z, &squared, tmp_is_one); - j_less_than_v &= !j.ct_eq(&v); - k = u32::conditional_select(&j, &k, tmp_is_one); - z = #name::conditional_select(&z, &new_z, j_less_than_v); - } - - let result = x * &z; - x = #name::conditional_select(&result, &x, b.ct_eq(&#name::one())); - z = z.square(); - b *= &z; - v = k; - } - - ::ff::derive::subtle::CtOption::new( - x, - (x * &x).ct_eq(self), // Only return Some if it's the square root. - ) - } - } else { - syn::Error::new_spanned( - &name, - "ff_derive can't generate a square root function for this field.", - ) - .to_compile_error() - }; - - // Compute R^2 mod m - let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs); - - let r = biguint_to_u64_vec(r, limbs); - let modulus_le_bytes = ReprEndianness::Little.modulus_repr(modulus, limbs * 8); - let modulus = biguint_to_real_u64_vec(modulus.clone(), limbs); - - // Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1 - let mut inv = 1u64; - for _ in 0..63 { - inv = inv.wrapping_mul(inv); - inv = inv.wrapping_mul(modulus[0]); - } - inv = inv.wrapping_neg(); - - ( - quote! { - type REPR_BYTES = [u8; #bytes]; - type REPR_BITS = REPR_BYTES; - - /// This is the modulus m of the prime field - const MODULUS: REPR_BITS = [#(#modulus_le_bytes,)*]; - - /// This is the modulus m of the prime field in limb form - const MODULUS_LIMBS: #name = #name([#(#modulus,)*]); - - /// The number of bits needed to represent the modulus. - const MODULUS_BITS: u32 = #modulus_num_bits; - - /// The number of bits that must be shaved from the beginning of - /// the representation when randomly sampling. - const REPR_SHAVE_BITS: u32 = #repr_shave_bits; - - /// 2^{limbs*64} mod m - const R: #name = #name(#r); - - /// 2^{limbs*64*2} mod m - const R2: #name = #name(#r2); - - /// -(m^{-1} mod m) mod m - const INV: u64 = #inv; - - /// Multiplicative generator of `MODULUS` - 1 order, also quadratic - /// nonresidue. - const GENERATOR: #name = #name(#generator); - - /// 2^s * t = MODULUS - 1 with t odd - const S: u32 = #s; - - /// 2^s root of unity computed by GENERATOR^t - const ROOT_OF_UNITY: #name = #name(#root_of_unity); - }, - sqrt_impl, - ) -} - -/// Implement PrimeField for the derived type. -fn prime_field_impl( - name: &syn::Ident, - repr: &syn::Ident, - modulus: &BigUint, - endianness: &ReprEndianness, - limbs: usize, - sqrt_impl: proc_macro2::TokenStream, -) -> proc_macro2::TokenStream { - // Returns r{n} as an ident. - fn get_temp(n: usize) -> syn::Ident { - syn::Ident::new(&format!("r{}", n), proc_macro2::Span::call_site()) - } - - // The parameter list for the mont_reduce() internal method. - // r0: u64, mut r1: u64, mut r2: u64, ... - let mut mont_paramlist = proc_macro2::TokenStream::new(); - mont_paramlist.append_separated( - (0..(limbs * 2)).map(|i| (i, get_temp(i))).map(|(i, x)| { - if i != 0 { - quote! {mut #x: u64} - } else { - quote! {#x: u64} - } - }), - proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), - ); - - // Implement montgomery reduction for some number of limbs - fn mont_impl(limbs: usize) -> proc_macro2::TokenStream { - let mut gen = proc_macro2::TokenStream::new(); - - for i in 0..limbs { - { - let temp = get_temp(i); - gen.extend(quote! { - let k = #temp.wrapping_mul(INV); - let (_, carry) = ::ff::derive::mac(#temp, k, MODULUS_LIMBS.0[0], 0); - }); - } - - for j in 1..limbs { - let temp = get_temp(i + j); - gen.extend(quote! { - let (#temp, carry) = ::ff::derive::mac(#temp, k, MODULUS_LIMBS.0[#j], carry); - }); - } - - let temp = get_temp(i + limbs); - - if i == 0 { - gen.extend(quote! { - let (#temp, carry2) = ::ff::derive::adc(#temp, 0, carry); - }); - } else { - gen.extend(quote! { - let (#temp, carry2) = ::ff::derive::adc(#temp, carry2, carry); - }); - } - } - - for i in 0..limbs { - let temp = get_temp(limbs + i); - - gen.extend(quote! { - self.0[#i] = #temp; - }); - } - - gen - } - - fn sqr_impl(a: proc_macro2::TokenStream, limbs: usize) -> proc_macro2::TokenStream { - let mut gen = proc_macro2::TokenStream::new(); - - if limbs > 1 { - for i in 0..(limbs - 1) { - gen.extend(quote! { - let carry = 0; - }); - - for j in (i + 1)..limbs { - let temp = get_temp(i + j); - if i == 0 { - gen.extend(quote! { - let (#temp, carry) = ::ff::derive::mac(0, #a.0[#i], #a.0[#j], carry); - }); - } else { - gen.extend(quote! { - let (#temp, carry) = ::ff::derive::mac(#temp, #a.0[#i], #a.0[#j], carry); - }); - } - } - - let temp = get_temp(i + limbs); - - gen.extend(quote! { - let #temp = carry; - }); - } - - for i in 1..(limbs * 2) { - let temp0 = get_temp(limbs * 2 - i); - let temp1 = get_temp(limbs * 2 - i - 1); - - if i == 1 { - gen.extend(quote! { - let #temp0 = #temp1 >> 63; - }); - } else if i == (limbs * 2 - 1) { - gen.extend(quote! { - let #temp0 = #temp0 << 1; - }); - } else { - gen.extend(quote! { - let #temp0 = (#temp0 << 1) | (#temp1 >> 63); - }); - } - } - } else { - let temp1 = get_temp(1); - gen.extend(quote! { - let #temp1 = 0; - }); - } - - for i in 0..limbs { - let temp0 = get_temp(i * 2); - let temp1 = get_temp(i * 2 + 1); - if i == 0 { - gen.extend(quote! { - let (#temp0, carry) = ::ff::derive::mac(0, #a.0[#i], #a.0[#i], 0); - }); - } else { - gen.extend(quote! { - let (#temp0, carry) = ::ff::derive::mac(#temp0, #a.0[#i], #a.0[#i], carry); - }); - } - - gen.extend(quote! { - let (#temp1, carry) = ::ff::derive::adc(#temp1, 0, carry); - }); - } - - let mut mont_calling = proc_macro2::TokenStream::new(); - mont_calling.append_separated( - (0..(limbs * 2)).map(get_temp), - proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), - ); - - gen.extend(quote! { - let mut ret = *self; - ret.mont_reduce(#mont_calling); - ret - }); - - gen - } - - fn mul_impl( - a: proc_macro2::TokenStream, - b: proc_macro2::TokenStream, - limbs: usize, - ) -> proc_macro2::TokenStream { - let mut gen = proc_macro2::TokenStream::new(); - - for i in 0..limbs { - gen.extend(quote! { - let carry = 0; - }); - - for j in 0..limbs { - let temp = get_temp(i + j); - - if i == 0 { - gen.extend(quote! { - let (#temp, carry) = ::ff::derive::mac(0, #a.0[#i], #b.0[#j], carry); - }); - } else { - gen.extend(quote! { - let (#temp, carry) = ::ff::derive::mac(#temp, #a.0[#i], #b.0[#j], carry); - }); - } - } - - let temp = get_temp(i + limbs); - - gen.extend(quote! { - let #temp = carry; - }); - } - - let mut mont_calling = proc_macro2::TokenStream::new(); - mont_calling.append_separated( - (0..(limbs * 2)).map(get_temp), - proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), - ); - - gen.extend(quote! { - self.mont_reduce(#mont_calling); - }); - - gen - } - - /// Generates an implementation of multiplicative inversion within the target prime - /// field. - fn inv_impl( - a: proc_macro2::TokenStream, - name: &syn::Ident, - modulus: &BigUint, - ) -> proc_macro2::TokenStream { - // Addition chain for p - 2 - let mod_minus_2 = pow_fixed::generate(&a, modulus - BigUint::from(2u64)); - - quote! { - use ::ff::derive::subtle::ConstantTimeEq; - - // By Euler's theorem, if `a` is coprime to `p` (i.e. `gcd(a, p) = 1`), then: - // a^-1 ≡ a^(phi(p) - 1) mod p - // - // `ff_derive` requires that `p` is prime; in this case, `phi(p) = p - 1`, and - // thus: - // a^-1 ≡ a^(p - 2) mod p - let inv = { - #mod_minus_2 - }; - - ::ff::derive::subtle::CtOption::new(inv, !#a.ct_eq(&#name::zero())) - } - } - - let squaring_impl = sqr_impl(quote! {self}, limbs); - let multiply_impl = mul_impl(quote! {self}, quote! {other}, limbs); - let invert_impl = inv_impl(quote! {self}, name, modulus); - let montgomery_impl = mont_impl(limbs); - - // self.0[0].ct_eq(&other.0[0]) & self.0[1].ct_eq(&other.0[1]) & ... - let mut ct_eq_impl = proc_macro2::TokenStream::new(); - ct_eq_impl.append_separated( - (0..limbs).map(|i| quote! { self.0[#i].ct_eq(&other.0[#i]) }), - proc_macro2::Punct::new('&', proc_macro2::Spacing::Alone), - ); - - fn mont_reduce_params(a: proc_macro2::TokenStream, limbs: usize) -> proc_macro2::TokenStream { - // a.0[0], a.0[1], ..., 0, 0, 0, 0, ... - let mut mont_reduce_params = proc_macro2::TokenStream::new(); - mont_reduce_params.append_separated( - (0..limbs) - .map(|i| quote! { #a.0[#i] }) - .chain((0..limbs).map(|_| quote! {0})), - proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), - ); - mont_reduce_params - } - - let mont_reduce_self_params = mont_reduce_params(quote! {self}, limbs); - let mont_reduce_other_params = mont_reduce_params(quote! {other}, limbs); - - let from_repr_impl = endianness.from_repr(name, limbs); - let to_repr_impl = endianness.to_repr(quote! {#repr}, &mont_reduce_self_params, limbs); - - cfg_if::cfg_if! { - if #[cfg(feature = "bits")] { - let to_le_bits_impl = ReprEndianness::Little.to_repr( - quote! {::ff::derive::bitvec::array::BitArray::new}, - &mont_reduce_self_params, - limbs, - ); - - let prime_field_bits_impl = quote! { - impl ::ff::PrimeFieldBits for #name { - type ReprBits = REPR_BITS; - - fn to_le_bits(&self) -> ::ff::FieldBits { - #to_le_bits_impl - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new(MODULUS) - } - } - }; - } else { - let prime_field_bits_impl = quote! {}; - } - }; - - let top_limb_index = limbs - 1; - - quote! { - impl ::core::marker::Copy for #name { } - - impl ::core::clone::Clone for #name { - fn clone(&self) -> #name { - *self - } - } - - impl ::core::default::Default for #name { - fn default() -> #name { - use ::ff::Field; - #name::zero() - } - } - - impl ::ff::derive::subtle::ConstantTimeEq for #name { - fn ct_eq(&self, other: &#name) -> ::ff::derive::subtle::Choice { - use ::ff::PrimeField; - self.to_repr().ct_eq(&other.to_repr()) - } - } - - impl ::core::cmp::PartialEq for #name { - fn eq(&self, other: &#name) -> bool { - use ::ff::derive::subtle::ConstantTimeEq; - self.ct_eq(other).into() - } - } - - impl ::core::cmp::Eq for #name { } - - impl ::core::fmt::Debug for #name - { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - use ::ff::PrimeField; - write!(f, "{}({:?})", stringify!(#name), self.to_repr()) - } - } - - /// Elements are ordered lexicographically. - impl Ord for #name { - #[inline(always)] - fn cmp(&self, other: &#name) -> ::core::cmp::Ordering { - let mut a = *self; - a.mont_reduce( - #mont_reduce_self_params - ); - - let mut b = *other; - b.mont_reduce( - #mont_reduce_other_params - ); - - a.cmp_native(&b) - } - } - - impl PartialOrd for #name { - #[inline(always)] - fn partial_cmp(&self, other: &#name) -> Option<::core::cmp::Ordering> { - Some(self.cmp(other)) - } - } - - impl From for #name { - #[inline(always)] - fn from(val: u64) -> #name { - let mut raw = [0u64; #limbs]; - raw[0] = val; - #name(raw) * R2 - } - } - - impl From<#name> for #repr { - fn from(e: #name) -> #repr { - use ::ff::PrimeField; - e.to_repr() - } - } - - impl<'a> From<&'a #name> for #repr { - fn from(e: &'a #name) -> #repr { - use ::ff::PrimeField; - e.to_repr() - } - } - - impl ::ff::derive::subtle::ConditionallySelectable for #name { - fn conditional_select(a: &#name, b: &#name, choice: ::ff::derive::subtle::Choice) -> #name { - let mut res = [0u64; #limbs]; - for i in 0..#limbs { - res[i] = u64::conditional_select(&a.0[i], &b.0[i], choice); - } - #name(res) - } - } - - impl ::core::ops::Neg for #name { - type Output = #name; - - #[inline] - fn neg(self) -> #name { - use ::ff::Field; - - let mut ret = self; - if !ret.is_zero_vartime() { - let mut tmp = MODULUS_LIMBS; - tmp.sub_noborrow(&ret); - ret = tmp; - } - ret - } - } - - impl<'r> ::core::ops::Add<&'r #name> for #name { - type Output = #name; - - #[inline] - fn add(self, other: &#name) -> #name { - use ::core::ops::AddAssign; - - let mut ret = self; - ret.add_assign(other); - ret - } - } - - impl ::core::ops::Add for #name { - type Output = #name; - - #[inline] - fn add(self, other: #name) -> Self { - self + &other - } - } - - impl<'r> ::core::ops::AddAssign<&'r #name> for #name { - #[inline] - fn add_assign(&mut self, other: &#name) { - // This cannot exceed the backing capacity. - self.add_nocarry(other); - - // However, it may need to be reduced. - self.reduce(); - } - } - - impl ::core::ops::AddAssign for #name { - #[inline] - fn add_assign(&mut self, other: #name) { - self.add_assign(&other); - } - } - - impl<'r> ::core::ops::Sub<&'r #name> for #name { - type Output = #name; - - #[inline] - fn sub(self, other: &#name) -> Self { - use ::core::ops::SubAssign; - - let mut ret = self; - ret.sub_assign(other); - ret - } - } - - impl ::core::ops::Sub for #name { - type Output = #name; - - #[inline] - fn sub(self, other: #name) -> Self { - self - &other - } - } - - impl<'r> ::core::ops::SubAssign<&'r #name> for #name { - #[inline] - fn sub_assign(&mut self, other: &#name) { - // If `other` is larger than `self`, we'll need to add the modulus to self first. - if other.cmp_native(self) == ::core::cmp::Ordering::Greater { - self.add_nocarry(&MODULUS_LIMBS); - } - - self.sub_noborrow(other); - } - } - - impl ::core::ops::SubAssign for #name { - #[inline] - fn sub_assign(&mut self, other: #name) { - self.sub_assign(&other); - } - } - - impl<'r> ::core::ops::Mul<&'r #name> for #name { - type Output = #name; - - #[inline] - fn mul(self, other: &#name) -> Self { - use ::core::ops::MulAssign; - - let mut ret = self; - ret.mul_assign(other); - ret - } - } - - impl ::core::ops::Mul for #name { - type Output = #name; - - #[inline] - fn mul(self, other: #name) -> Self { - self * &other - } - } - - impl<'r> ::core::ops::MulAssign<&'r #name> for #name { - #[inline] - fn mul_assign(&mut self, other: &#name) - { - #multiply_impl - } - } - - impl ::core::ops::MulAssign for #name { - #[inline] - fn mul_assign(&mut self, other: #name) - { - self.mul_assign(&other); - } - } - - impl ::ff::PrimeField for #name { - type Repr = #repr; - - fn from_repr(r: #repr) -> ::ff::derive::subtle::CtOption<#name> { - #from_repr_impl - - // Try to subtract the modulus - let borrow = r.0.iter().zip(MODULUS_LIMBS.0.iter()).fold(0, |borrow, (a, b)| { - ::ff::derive::sbb(*a, *b, borrow).1 - }); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = ::ff::derive::subtle::Choice::from((borrow as u8) & 1); - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - ::ff::derive::subtle::CtOption::new(r * &R2, is_some) - } - - fn from_repr_vartime(r: #repr) -> Option<#name> { - #from_repr_impl - - if r.is_valid() { - Some(r * R2) - } else { - None - } - } - - fn to_repr(&self) -> #repr { - #to_repr_impl - } - - #[inline(always)] - fn is_odd(&self) -> ::ff::derive::subtle::Choice { - let mut r = *self; - r.mont_reduce( - #mont_reduce_self_params - ); - - // TODO: This looks like a constant-time result, but r.mont_reduce() is - // currently implemented using variable-time code. - ::ff::derive::subtle::Choice::from((r.0[0] & 1) as u8) - } - - const NUM_BITS: u32 = MODULUS_BITS; - - const CAPACITY: u32 = Self::NUM_BITS - 1; - - fn multiplicative_generator() -> Self { - GENERATOR - } - - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - - const S: u32 = S; - - fn root_of_unity() -> Self { - ROOT_OF_UNITY - } - } - - #prime_field_bits_impl - - impl ::ff::Field for #name { - /// Computes a uniformly random element using rejection sampling. - fn random(mut rng: impl ::ff::derive::rand_core::RngCore) -> Self { - loop { - let mut tmp = { - let mut repr = [0u64; #limbs]; - for i in 0..#limbs { - repr[i] = rng.next_u64(); - } - #name(repr) - }; - - // Mask away the unused most-significant bits. - // Note: In some edge cases, `REPR_SHAVE_BITS` could be 64, in which case - // `0xfff... >> REPR_SHAVE_BITS` overflows. So use `checked_shr` instead. - // This is always sufficient because we will have at most one spare limb - // to accommodate values of up to twice the modulus. - tmp.0.as_mut()[#top_limb_index] &= 0xffffffffffffffffu64.checked_shr(REPR_SHAVE_BITS).unwrap_or(0); - - if tmp.is_valid() { - return tmp - } - } - } - - #[inline] - fn zero() -> Self { - #name([0; #limbs]) - } - - const ZERO: Self = #name([0; #limbs]); - - #[inline] - fn one() -> Self { - R - } - - const ONE: Self = R; - - #[inline] - fn is_zero(&self) -> ::ff::derive::subtle::Choice { - use ::ff::derive::subtle::ConstantTimeEq; - self.ct_eq(&Self::zero()) - } - - #[inline] - fn is_zero_vartime(&self) -> bool { - self.0.iter().all(|&e| e == 0) - } - - #[inline] - fn double(&self) -> Self { - let mut ret = *self; - - // This cannot exceed the backing capacity. - let mut last = 0; - for i in &mut ret.0 { - let tmp = *i >> 63; - *i <<= 1; - *i |= last; - last = tmp; - } - - // However, it may need to be reduced. - ret.reduce(); - - ret - } - - fn invert(&self) -> ::ff::derive::subtle::CtOption { - #invert_impl - } - - #[inline] - fn square(&self) -> Self - { - #squaring_impl - } - - fn sqrt(&self) -> ::ff::derive::subtle::CtOption { - #sqrt_impl - } - } - - impl #name { - /// Compares two elements in native representation. This is only used - /// internally. - #[inline(always)] - fn cmp_native(&self, other: &#name) -> ::core::cmp::Ordering { - for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { - if a < b { - return ::core::cmp::Ordering::Less - } else if a > b { - return ::core::cmp::Ordering::Greater - } - } - - ::core::cmp::Ordering::Equal - } - - /// Determines if the element is really in the field. This is only used - /// internally. - #[inline(always)] - fn is_valid(&self) -> bool { - // The Ord impl calls `reduce`, which in turn calls `is_valid`, so we use - // this internal function to eliminate the cycle. - self.cmp_native(&MODULUS_LIMBS) == ::core::cmp::Ordering::Less - } - - #[inline(always)] - fn add_nocarry(&mut self, other: &#name) { - let mut carry = 0; - - for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - let (new_a, new_carry) = ::ff::derive::adc(*a, *b, carry); - *a = new_a; - carry = new_carry; - } - } - - #[inline(always)] - fn sub_noborrow(&mut self, other: &#name) { - let mut borrow = 0; - - for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - let (new_a, new_borrow) = ::ff::derive::sbb(*a, *b, borrow); - *a = new_a; - borrow = new_borrow; - } - } - - /// Subtracts the modulus from this element if this element is not in the - /// field. Only used interally. - #[inline(always)] - fn reduce(&mut self) { - if !self.is_valid() { - self.sub_noborrow(&MODULUS_LIMBS); - } - } - - #[allow(clippy::too_many_arguments)] - #[inline(always)] - fn mont_reduce( - &mut self, - #mont_paramlist - ) - { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - #montgomery_impl - - self.reduce(); - } - } - } -} From faadd4608f2c46c41f3631462777a2aae0b89617 Mon Sep 17 00:00:00 2001 From: Marc Rosen Date: Thu, 6 Apr 2023 16:31:19 -0400 Subject: [PATCH 4/8] Upgrade subtle dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d8c299c..a3ec72a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ bitvec = { version = "1", default-features = false, optional = true } byteorder = { version = "1", default-features = false, optional = true } ff_derive = { version = "0.12", path = "ff_derive", optional = true } rand_core = { version = "0.6", default-features = false } -subtle = { version = "2.2.1", default-features = false, features = ["i128"] } +subtle = { version = "2.5.0", default-features = false, features = ["i128"] } [dev-dependencies] rand = "0.8" From 1a4c6138e2e76e13f8d54fae81857e2cea3cbc4d Mon Sep 17 00:00:00 2001 From: Marc Rosen Date: Thu, 6 Apr 2023 16:34:52 -0400 Subject: [PATCH 5/8] Be more permissive with subtle dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a3ec72a..10725a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ bitvec = { version = "1", default-features = false, optional = true } byteorder = { version = "1", default-features = false, optional = true } ff_derive = { version = "0.12", path = "ff_derive", optional = true } rand_core = { version = "0.6", default-features = false } -subtle = { version = "2.5.0", default-features = false, features = ["i128"] } +subtle = { version = ">=2.2.0,<2.6.0", default-features = false, features = ["i128"] } [dev-dependencies] rand = "0.8" From be5c8ff38750f37c8f6307ab39790300f0fcc277 Mon Sep 17 00:00:00 2001 From: Marc Rosen Date: Fri, 26 Jul 2024 14:32:28 -0400 Subject: [PATCH 6/8] chore: bump rust version --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 3ebf789..aaceec0 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.56.0 +1.80.0 From 8385746572cde82920947763e634c933d36d4557 Mon Sep 17 00:00:00 2001 From: Marc Rosen Date: Fri, 26 Jul 2024 14:32:42 -0400 Subject: [PATCH 7/8] chore: allow more subtle versions --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 10725a6..a0d0f5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ bitvec = { version = "1", default-features = false, optional = true } byteorder = { version = "1", default-features = false, optional = true } ff_derive = { version = "0.12", path = "ff_derive", optional = true } rand_core = { version = "0.6", default-features = false } -subtle = { version = ">=2.2.0,<2.6.0", default-features = false, features = ["i128"] } +subtle = { version = ">=2.6.0", default-features = false, features = ["i128"] } [dev-dependencies] rand = "0.8" From c29da06f50c67fe9e7361c26f61ac831915244f8 Mon Sep 17 00:00:00 2001 From: Marc Rosen Date: Fri, 21 Mar 2025 14:32:05 -0400 Subject: [PATCH 8/8] use as_mut_slice() instead of as_ref() The latter was causing issues for type inference. --- ff_codegen/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ff_codegen/src/lib.rs b/ff_codegen/src/lib.rs index 52ea99a..3470003 100644 --- a/ff_codegen/src/lib.rs +++ b/ff_codegen/src/lib.rs @@ -1028,7 +1028,7 @@ fn prime_field_impl( // `0xfff... >> REPR_SHAVE_BITS` overflows. So use `checked_shr` instead. // This is always sufficient because we will have at most one spare limb // to accommodate values of up to twice the modulus. - tmp.0.as_mut()[#top_limb_index] &= 0xffffffffffffffffu64.checked_shr(REPR_SHAVE_BITS).unwrap_or(0); + tmp.0.as_mut_slice()[#top_limb_index] &= 0xffffffffffffffffu64.checked_shr(REPR_SHAVE_BITS).unwrap_or(0); if tmp.is_valid() { return tmp