From 183faaaac33cac6ef95f4b10b84b9c44445ad038 Mon Sep 17 00:00:00 2001 From: Ari Date: Tue, 30 Sep 2025 19:41:14 +0200 Subject: [PATCH 1/2] adding in montu128 helpers --- ff/src/fields/models/fp/montgomery_backend.rs | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index ad487ffa6..765855a2f 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -493,7 +493,11 @@ pub trait MontConfig: 'static + Sync + Send + Sized { // return Fp::zero(); // } let fe = Self::from_bigint_mixed::(x.magnitude); - if x.is_positive { fe } else { -fe } + if x.is_positive { + fe + } else { + -fe + } } /// Construct from a signed big integer with high 32-bit tail and K low 64-bit limbs. @@ -503,13 +507,20 @@ pub trait MontConfig: 'static + Sync + Send + Sized { fn from_signed_bigint_hi32( x: crate::biginteger::SignedBigIntHi32, ) -> Fp, N> { - debug_assert!(KPLUS1 == K + 1, "from_signed_bigint_hi32 requires KPLUS1 = K + 1"); + debug_assert!( + KPLUS1 == K + 1, + "from_signed_bigint_hi32 requires KPLUS1 = K + 1" + ); // if x.is_zero() { // return Fp::zero(); // } let mag = x.magnitude_as_bigint_nplus1::(); let fe = Self::from_bigint_mixed::(mag); - if x.is_positive() { fe } else { -fe } + if x.is_positive() { + fe + } else { + -fe + } } #[inline] @@ -882,9 +893,7 @@ impl, const N: usize> Fp, N> { /// Implementation folds from high to low using the existing N+1 Barrett kernel. /// Precondition: L >= N. For performance, prefer small L close to N..N+3 when possible. #[inline(always)] - pub fn from_barrett_reduce( - unreduced: BigInt, - ) -> Self { + pub fn from_barrett_reduce(unreduced: BigInt) -> Self { debug_assert!(NPLUS1 == N + 1); debug_assert!(L >= N); @@ -1094,6 +1103,14 @@ impl, const N: usize> Fp, N> { *self = self.const_cios_mul_rhs_hi2(hi as u64, (hi >> 64) as u64); } + /// Returns self * rhs_high_limbs, where RHS is zero in low N-2 limbs and has its top two + /// limbs provided by `hi` (low 64 -> limb N-2, high 64 -> limb N-1). Equivalent to K=2. + /// At the cost 2 extra words of storage uses no bit shift instructions to extract higher limbs + /// as in mul_hi_u128 + #[inline] + pub const fn mul_hi_bigint_u128(self, big_int_repre: [u64; 4]) -> Self { + self.const_cios_mul_rhs_hi2(big_int_repre[2], big_int_repre[3]) + } /// Returns self * rhs_high_limbs, where RHS is zero in low N-2 limbs and has its top two /// limbs provided by `hi` (low 64 -> limb N-2, high 64 -> limb N-1). Equivalent to K=2. #[inline] From fee4ab253cf56c0eb054cde03ad2c599db0f0317 Mon Sep 17 00:00:00 2001 From: Ari Date: Tue, 30 Sep 2025 22:25:30 +0200 Subject: [PATCH 2/2] adding in unchecked to prevent unnecessary mont-reductions --- ff/src/fields/models/fp/mod.rs | 45 ++++++++----------- ff/src/fields/models/fp/montgomery_backend.rs | 8 ++++ ff/src/fields/prime.rs | 3 ++ 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index 30af6f46f..993880be5 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -4,8 +4,9 @@ use crate::{ }; use allocative::Allocative; use ark_serialize::{ - buffer_byte_size, CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, + CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize, CanonicalSerializeWithFlags, Compress, EmptyFlags, Flags, SerializationError, Valid, Validate, + buffer_byte_size, }; use ark_std::{ cmp::*, @@ -98,6 +99,11 @@ pub trait FpConfig: Send + Sync + 'static + Sized { /// this range. fn from_bigint(other: BigInt) -> Option>; + /// Construct a field element from an integer in the range + /// `0..(Self::MODULUS - 1)`. Returns `None` if the integer is outside + /// this range (but do not do any Reductions) + fn from_bigint_unchecked(other: BigInt) -> Option>; + /// Convert a field element to an integer in the range `0..(Self::MODULUS - /// 1)`. fn into_bigint(other: Fp) -> BigInt; @@ -371,6 +377,11 @@ impl, const N: usize> PrimeField for Fp { P::into_bigint(self) } + #[inline] + fn from_bigint_unchecked(r: BigInt) -> Option { + P::from_bigint_unchecked(r) + } + #[inline] fn from_u64(r: u64) -> Option { P::from_u64::(r) @@ -433,11 +444,7 @@ impl, const N: usize> From for Fp { impl, const N: usize> From for Fp { fn from(other: i128) -> Self { let abs = Self::from(other.unsigned_abs()); - if other.is_positive() { - abs - } else { - -abs - } + if other.is_positive() { abs } else { -abs } } } @@ -464,11 +471,7 @@ impl, const N: usize> From for Fp { impl, const N: usize> From for Fp { fn from(other: i64) -> Self { let abs = Self::from(other.unsigned_abs()); - if other.is_positive() { - abs - } else { - -abs - } + if other.is_positive() { abs } else { -abs } } } @@ -485,11 +488,7 @@ impl, const N: usize> From for Fp { impl, const N: usize> From for Fp { fn from(other: i32) -> Self { let abs = Self::from(other.unsigned_abs()); - if other.is_positive() { - abs - } else { - -abs - } + if other.is_positive() { abs } else { -abs } } } @@ -506,11 +505,7 @@ impl, const N: usize> From for Fp { impl, const N: usize> From for Fp { fn from(other: i16) -> Self { let abs = Self::from(other.unsigned_abs()); - if other.is_positive() { - abs - } else { - -abs - } + if other.is_positive() { abs } else { -abs } } } @@ -527,11 +522,7 @@ impl, const N: usize> From for Fp { impl, const N: usize> From for Fp { fn from(other: i8) -> Self { let abs = Self::from(other.unsigned_abs()); - if other.is_positive() { - abs - } else { - -abs - } + if other.is_positive() { abs } else { -abs } } } @@ -554,7 +545,7 @@ impl, const N: usize> ark_std::rand::distributions::Distribution< u64::MAX >> shave_bits }; - if let Some(val) = tmp.0 .0.last_mut() { + if let Some(val) = tmp.0.0.last_mut() { *val &= mask } diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index 765855a2f..d2de50090 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -462,6 +462,10 @@ pub trait MontConfig: 'static + Sync + Send + Sized { } } + fn from_bigint_unchecked(r: BigInt) -> Option, N>> { + Some(Fp::new_unchecked(r)) + } + fn from_bigint(r: BigInt) -> Option, N>> { let mut r = Fp::new_unchecked(r); if r.is_zero() { @@ -845,6 +849,10 @@ impl, const N: usize> FpConfig for MontBackend { T::from_bigint(r) } + fn from_bigint_unchecked(r: BigInt) -> Option> { + T::from_bigint_unchecked(r) + } + #[inline] #[allow(clippy::modulo_one)] fn into_bigint(a: Fp) -> BigInt { diff --git a/ff/src/fields/prime.rs b/ff/src/fields/prime.rs index 67a7f0db0..9ae26d83e 100644 --- a/ff/src/fields/prime.rs +++ b/ff/src/fields/prime.rs @@ -57,6 +57,9 @@ pub trait PrimeField: /// Converts an element of the prime field into an integer in the range 0..(p - 1). fn into_bigint(self) -> Self::BigInt; + /// Construct a prime field element from an integer in the range 0..(p - 1) (no reductions) + fn from_bigint_unchecked(repr: Self::BigInt) -> Option; + /// Creates a field element from a `u64`. /// Returns `None` if the `u64` is larger than or equal to the modulus. fn from_u64(val: u64) -> Option;