From 8918f1d27656be9c1add7b34c038242577ab4e94 Mon Sep 17 00:00:00 2001 From: serhii023 Date: Wed, 2 Apr 2025 11:46:47 +0300 Subject: [PATCH 1/5] aditional logic for special case of sqrt --- ff/src/biginteger/mod.rs | 7 +++ ff/src/fields/models/fp/montgomery_backend.rs | 50 +++++++++++++++++-- ff/src/fields/sqrt.rs | 26 ++++++++++ 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/ff/src/biginteger/mod.rs b/ff/src/biginteger/mod.rs index c8632db29..3f0e44045 100644 --- a/ff/src/biginteger/mod.rs +++ b/ff/src/biginteger/mod.rs @@ -157,6 +157,13 @@ impl BigInt { (((self.0[0] << 62) >> 62) % 4) as u8 } + #[doc(hidden)] + pub const fn mod_8(&self) -> u8 { + // To compute n % 8, we need to simply look at the + // 3 least significant bits of n, and check their value mod 8. + (((self.0[0] << 61) >> 61) % 8) as u8 + } + /// Compute a right shift of `self` /// This is equivalent to a (saturating) division by 2. #[doc(hidden)] diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index a58c5ca03..1e3206a22 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -93,6 +93,37 @@ pub trait MontConfig: 'static + Sync + Send + Sized { } }; + /// (MODULUS + 3) / 8 when MODULUS % 8 == 5. Used for square root precomputations. + #[doc(hidden)] + const MODULUS_PLUS_THREE_DIV_EIGHT: Option> = { + match Self::MODULUS.mod_8() == 5 { + true => { + let (modulus_plus_three, carry) = Self::MODULUS.const_add_with_carry(&BigInt!("3")); + let mut result = modulus_plus_three.divide_by_2_round_down(); + // Since modulus_plus_one is even, dividing by 2 results in a MSB of 0. + // Thus we can set MSB to `carry` to get the correct result of (MODULUS + 1) // 2: + result.0[N - 1] |= (carry as u64) << 63; + result = result.divide_by_2_round_down(); + + Some(result.divide_by_2_round_down()) + }, + false => None, + } + }; + + /// (MODULUS - 1) / 4 when MODULUS % 8 == 5. Used for square root precomputations. + #[doc(hidden)] + const MODULUS_MINUS_ONE_DIV_FOUR: Option> = { + match Self::MODULUS.mod_8() == 5 { + true => { + let (modulus_plus_three, borrow) = Self::MODULUS.const_sub_with_borrow(&BigInt::one()); + let mut result = modulus_plus_three.divide_by_2_round_down(); + Some(result.divide_by_2_round_down()) + }, + false => None, + } + }; + /// Sets `a = a + b`. #[inline(always)] fn add_assign(a: &mut Fp, N>, b: &Fp, N>) { @@ -548,12 +579,21 @@ pub const fn sqrt_precomputation>( }), None => None, }, - _ => Some(SqrtPrecomputation::TonelliShanks { - two_adicity: >::TWO_ADICITY, - quadratic_nonresidue_to_trace: T::TWO_ADIC_ROOT_OF_UNITY, - trace_of_modulus_minus_one_div_two: + _ => match T::MODULUS.mod_8() { + 5 => match (T::MODULUS_PLUS_THREE_DIV_EIGHT.as_ref(), T::MODULUS_MINUS_ONE_DIV_FOUR.as_ref()) { + (Some(BigInt(modulus_plus_three_div_eight)), Some(BigInt(modulus_minus_one_div_four))) => Some(SqrtPrecomputation::Case5Mod8 { + modulus_plus_three_div_eight, + modulus_minus_one_div_four, + }), + _ => None, + }, + _ => Some(SqrtPrecomputation::TonelliShanks { + two_adicity: >::TWO_ADICITY, + quadratic_nonresidue_to_trace: T::TWO_ADIC_ROOT_OF_UNITY, + trace_of_modulus_minus_one_div_two: &, N>>::TRACE_MINUS_ONE_DIV_TWO.0, - }), + }), + } } } diff --git a/ff/src/fields/sqrt.rs b/ff/src/fields/sqrt.rs index 6f3525988..e305fc7aa 100644 --- a/ff/src/fields/sqrt.rs +++ b/ff/src/fields/sqrt.rs @@ -75,8 +75,14 @@ pub enum SqrtPrecomputation { Case3Mod4 { modulus_plus_one_div_four: &'static [u64], }, + /// To be used when the modulus is 5 mod 8. + Case5Mod8 { + modulus_plus_three_div_eight: &'static [u64], + modulus_minus_one_div_four: &'static [u64], + }, } + impl SqrtPrecomputation { pub fn sqrt(&self, elem: &F) -> Option { match self { @@ -144,6 +150,26 @@ impl SqrtPrecomputation { let result = elem.pow(modulus_plus_one_div_four.as_ref()); (result.square() == *elem).then_some(result) }, + Self::Case5Mod8 { + modulus_plus_three_div_eight, + modulus_minus_one_div_four, + } => { + let result; + + // We have different solutions, if check_value is 1 or -1. + let check_value = elem.pow(modulus_minus_one_div_four.as_ref()); + if check_value.is_one() { + result = elem.pow(modulus_plus_three_div_eight.as_ref()); + } else if check_value.neg().is_one() { + let two: F = 2.into(); + result = elem.pow(modulus_plus_three_div_eight.as_ref()) + .mul(two.pow(modulus_minus_one_div_four.as_ref())) + } else { + return None; + } + + (result.square() == *elem).then_some(result) + }, } } } From bebc3d8fd8ba208b9118ce770a2b955359a3b0f8 Mon Sep 17 00:00:00 2001 From: serhii023 Date: Wed, 2 Apr 2025 13:11:56 +0300 Subject: [PATCH 2/5] bug fix for zero case --- ff/src/fields/sqrt.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ff/src/fields/sqrt.rs b/ff/src/fields/sqrt.rs index e305fc7aa..7c16ecad9 100644 --- a/ff/src/fields/sqrt.rs +++ b/ff/src/fields/sqrt.rs @@ -154,6 +154,10 @@ impl SqrtPrecomputation { modulus_plus_three_div_eight, modulus_minus_one_div_four, } => { + if elem.is_zero() { + return Some(F::zero()); + } + let result; // We have different solutions, if check_value is 1 or -1. From 087aad3c000fe16e7bc65351582c300b44001b98 Mon Sep 17 00:00:00 2001 From: serhii023 Date: Wed, 2 Apr 2025 13:52:08 +0300 Subject: [PATCH 3/5] cargo fmt --- ff/src/fields/models/fp/montgomery_backend.rs | 17 ++++++++++++----- ff/src/fields/sqrt.rs | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index 1e3206a22..5e6fa595c 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -116,7 +116,8 @@ pub trait MontConfig: 'static + Sync + Send + Sized { const MODULUS_MINUS_ONE_DIV_FOUR: Option> = { match Self::MODULUS.mod_8() == 5 { true => { - let (modulus_plus_three, borrow) = Self::MODULUS.const_sub_with_borrow(&BigInt::one()); + let (modulus_plus_three, borrow) = + Self::MODULUS.const_sub_with_borrow(&BigInt::one()); let mut result = modulus_plus_three.divide_by_2_round_down(); Some(result.divide_by_2_round_down()) }, @@ -580,8 +581,14 @@ pub const fn sqrt_precomputation>( None => None, }, _ => match T::MODULUS.mod_8() { - 5 => match (T::MODULUS_PLUS_THREE_DIV_EIGHT.as_ref(), T::MODULUS_MINUS_ONE_DIV_FOUR.as_ref()) { - (Some(BigInt(modulus_plus_three_div_eight)), Some(BigInt(modulus_minus_one_div_four))) => Some(SqrtPrecomputation::Case5Mod8 { + 5 => match ( + T::MODULUS_PLUS_THREE_DIV_EIGHT.as_ref(), + T::MODULUS_MINUS_ONE_DIV_FOUR.as_ref(), + ) { + ( + Some(BigInt(modulus_plus_three_div_eight)), + Some(BigInt(modulus_minus_one_div_four)), + ) => Some(SqrtPrecomputation::Case5Mod8 { modulus_plus_three_div_eight, modulus_minus_one_div_four, }), @@ -591,9 +598,9 @@ pub const fn sqrt_precomputation>( two_adicity: >::TWO_ADICITY, quadratic_nonresidue_to_trace: T::TWO_ADIC_ROOT_OF_UNITY, trace_of_modulus_minus_one_div_two: - &, N>>::TRACE_MINUS_ONE_DIV_TWO.0, + &, N>>::TRACE_MINUS_ONE_DIV_TWO.0, }), - } + }, } } diff --git a/ff/src/fields/sqrt.rs b/ff/src/fields/sqrt.rs index 7c16ecad9..89f7bd061 100644 --- a/ff/src/fields/sqrt.rs +++ b/ff/src/fields/sqrt.rs @@ -82,7 +82,6 @@ pub enum SqrtPrecomputation { }, } - impl SqrtPrecomputation { pub fn sqrt(&self, elem: &F) -> Option { match self { @@ -166,8 +165,9 @@ impl SqrtPrecomputation { result = elem.pow(modulus_plus_three_div_eight.as_ref()); } else if check_value.neg().is_one() { let two: F = 2.into(); - result = elem.pow(modulus_plus_three_div_eight.as_ref()) - .mul(two.pow(modulus_minus_one_div_four.as_ref())) + result = elem + .pow(modulus_plus_three_div_eight.as_ref()) + .mul(two.pow(modulus_minus_one_div_four.as_ref())) } else { return None; } From d0fa65c5317be887f5ce6ee0d229480a3f2b8b5d Mon Sep 17 00:00:00 2001 From: serhii023 Date: Wed, 2 Apr 2025 13:57:40 +0300 Subject: [PATCH 4/5] warning reduce --- ff/src/fields/models/fp/montgomery_backend.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index 5e6fa595c..353f9e3e1 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -116,9 +116,9 @@ pub trait MontConfig: 'static + Sync + Send + Sized { const MODULUS_MINUS_ONE_DIV_FOUR: Option> = { match Self::MODULUS.mod_8() == 5 { true => { - let (modulus_plus_three, borrow) = + let (modulus_plus_three, _) = Self::MODULUS.const_sub_with_borrow(&BigInt::one()); - let mut result = modulus_plus_three.divide_by_2_round_down(); + let result = modulus_plus_three.divide_by_2_round_down(); Some(result.divide_by_2_round_down()) }, false => None, From b665879e3975ffd54804aedda688fab513f874ef Mon Sep 17 00:00:00 2001 From: serhii023 Date: Wed, 2 Apr 2025 13:59:07 +0300 Subject: [PATCH 5/5] cargo fmt --- ff/src/fields/models/fp/montgomery_backend.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ff/src/fields/models/fp/montgomery_backend.rs b/ff/src/fields/models/fp/montgomery_backend.rs index 353f9e3e1..8dfade589 100644 --- a/ff/src/fields/models/fp/montgomery_backend.rs +++ b/ff/src/fields/models/fp/montgomery_backend.rs @@ -116,8 +116,7 @@ pub trait MontConfig: 'static + Sync + Send + Sized { const MODULUS_MINUS_ONE_DIV_FOUR: Option> = { match Self::MODULUS.mod_8() == 5 { true => { - let (modulus_plus_three, _) = - Self::MODULUS.const_sub_with_borrow(&BigInt::one()); + let (modulus_plus_three, _) = Self::MODULUS.const_sub_with_borrow(&BigInt::one()); let result = modulus_plus_three.divide_by_2_round_down(); Some(result.divide_by_2_round_down()) },