From 60d80588b773cc226abd8e39156b292e71df15a1 Mon Sep 17 00:00:00 2001 From: Arvind Mukund Date: Thu, 2 Nov 2023 10:03:34 -0700 Subject: [PATCH 1/2] p521: Improve field arithmetic - sqn: Has an extra copy - sqrt: Can have simplified math Signed-off-by: Arvind Mukund --- p521/src/arithmetic/field.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/p521/src/arithmetic/field.rs b/p521/src/arithmetic/field.rs index 9651a2d4..10f13a55 100644 --- a/p521/src/arithmetic/field.rs +++ b/p521/src/arithmetic/field.rs @@ -201,8 +201,8 @@ impl FieldElement { /// Returns self^(2^n) mod p const fn sqn(&self, n: usize) -> Self { - let mut x = *self; - let mut i = 0; + let mut x = self.square(); + let mut i = 1; while i < n { x = x.square(); i += 1; @@ -277,21 +277,9 @@ impl FieldElement { /// Returns the square root of self mod p, or `None` if no square root /// exists. pub fn sqrt(&self) -> CtOption { - // Tonelli-Shank's algorithm for q mod 4 = 3 (i.e. Shank's algorithm) - // https://eprint.iacr.org/2012/685.pdf - let w = self.pow_vartime(&[ - 0x0000000000000000, - 0x0000000000000000, - 0x0000000000000000, - 0x0000000000000000, - 0x0000000000000000, - 0x0000000000000000, - 0x0000000000000000, - 0x0000000000000000, - 0x0000000000000080, - ]); - - CtOption::new(w, w.square().ct_eq(self)) + // See explanation @ https://github.com/RustCrypto/elliptic-curves/pull/946#discussion_r1380465035 + let sqrt = self.sqn(519); + CtOption::new(sqrt, sqrt.square().ct_eq(self)) } /// Relax a tight field element into a loose one. From 0d947766119cd870875d4e25c2da81086bef3b41 Mon Sep 17 00:00:00 2001 From: Arvind Mukund Date: Thu, 2 Nov 2023 10:59:42 -0700 Subject: [PATCH 2/2] Inline docs Signed-off-by: Arvind Mukund --- p521/src/arithmetic/field.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/p521/src/arithmetic/field.rs b/p521/src/arithmetic/field.rs index 10f13a55..1f75aca7 100644 --- a/p521/src/arithmetic/field.rs +++ b/p521/src/arithmetic/field.rs @@ -276,8 +276,16 @@ impl FieldElement { /// Returns the square root of self mod p, or `None` if no square root /// exists. + /// + /// # Implementation details + /// If _x_ has a sqrt, then due to Euler's criterion this implies x(p - 1)/2 = 1. + /// 1. x(p + 1)/2 = x. + /// 2. There's a special property due to _p ≡ 3 (mod 4)_ which implies _(p + 1)/4_ is an integer. + /// 3. We can rewrite `1.` as x((p+1)/4)2 + /// 4. x(p+1)/4 is the square root. + /// 5. This is simplified as (2251 - 1 + 1) /4 = 2519 + /// 6. Hence, x2519 is the square root iff _result.square() == self_ pub fn sqrt(&self) -> CtOption { - // See explanation @ https://github.com/RustCrypto/elliptic-curves/pull/946#discussion_r1380465035 let sqrt = self.sqn(519); CtOption::new(sqrt, sqrt.square().ct_eq(self)) }