From 70dcc5c82f5d48ff64ddf52d40160fa5b2c83792 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sun, 13 Jul 2025 00:51:56 +0200 Subject: [PATCH 1/9] `DecafPoint` is always torsion free --- ed448-goldilocks/src/constants.rs | 6 ------ ed448-goldilocks/src/decaf/points.rs | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/ed448-goldilocks/src/constants.rs b/ed448-goldilocks/src/constants.rs index 2041cdd18..adb98c281 100644 --- a/ed448-goldilocks/src/constants.rs +++ b/ed448-goldilocks/src/constants.rs @@ -12,9 +12,3 @@ pub const DECAF_BASEPOINT: DecafPoint = DecafPoint(curve::twedwards::extended::E /// \ell = 2^\{446\} + 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d. /// $$ pub const EDWARDS_BASEPOINT_ORDER: EdwardsScalar = EdwardsScalar::new(ORDER); - -/// `BASEPOINT_ORDER` is the order of the Decaf448 basepoint, i.e., -/// $$ -/// \ell = 2^\{446\} + 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d. -/// $$ -pub const DECAF_BASEPOINT_ORDER: DecafScalar = DecafScalar::new(ORDER); diff --git a/ed448-goldilocks/src/decaf/points.rs b/ed448-goldilocks/src/decaf/points.rs index 1cf82e84f..d9ab1318e 100644 --- a/ed448-goldilocks/src/decaf/points.rs +++ b/ed448-goldilocks/src/decaf/points.rs @@ -1,4 +1,4 @@ -use crate::constants::{DECAF_BASEPOINT, DECAF_BASEPOINT_ORDER}; +use crate::constants::DECAF_BASEPOINT; use crate::curve::twedwards::extended::ExtendedPoint; use crate::field::FieldElement; use crate::*; @@ -226,7 +226,7 @@ impl CofactorGroup for DecafPoint { } fn is_torsion_free(&self) -> Choice { - (self * DECAF_BASEPOINT_ORDER).ct_eq(&Self::IDENTITY) + Choice::from(1) } } From eff37b17000d47d7114717d0dd7a7b1ab6756026 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Fri, 18 Jul 2025 15:45:28 +0200 Subject: [PATCH 2/9] Use `Uint::to_le_byte_array()` directly --- ed448-goldilocks/src/field/scalar.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ed448-goldilocks/src/field/scalar.rs b/ed448-goldilocks/src/field/scalar.rs index 0c2d9f05e..2d0dc3179 100644 --- a/ed448-goldilocks/src/field/scalar.rs +++ b/ed448-goldilocks/src/field/scalar.rs @@ -728,9 +728,7 @@ impl Scalar { /// Convert this `Scalar` to a little-endian byte array. pub fn to_bytes(&self) -> [u8; 56] { - let bytes = self.scalar.to_le_bytes(); - let output: [u8; 56] = core::array::from_fn(|i| bytes[i]); - output + self.scalar.to_le_byte_array().0 } /// Invert this scalar From 23938d277ad157446e3c905768eeae22e5f78f33 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Fri, 18 Jul 2025 15:48:01 +0200 Subject: [PATCH 3/9] Use `is_negative()` directly --- ed448-goldilocks/src/field/element.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ed448-goldilocks/src/field/element.rs b/ed448-goldilocks/src/field/element.rs index a1276a2ce..90e2d86f1 100644 --- a/ed448-goldilocks/src/field/element.rs +++ b/ed448-goldilocks/src/field/element.rs @@ -418,7 +418,7 @@ impl FieldElement { let e = b * c; let mut a = n * e; - a.conditional_negate(!Choice::from(a.0.retrieve().bit(0)) ^ square); + a.conditional_negate(!a.is_negative() ^ square); let c = e * ONE_MINUS_TWO_D; let b = c.square(); From 972302aaddb592eef7aa1541d1c86e1ad04480c3 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 19 Jul 2025 10:27:05 +0200 Subject: [PATCH 4/9] Enforce constant-time `FieldElement::square_n()` --- ed448-goldilocks/src/field/element.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ed448-goldilocks/src/field/element.rs b/ed448-goldilocks/src/field/element.rs index 90e2d86f1..ee17406e9 100644 --- a/ed448-goldilocks/src/field/element.rs +++ b/ed448-goldilocks/src/field/element.rs @@ -276,11 +276,11 @@ impl FieldElement { } /// Squares a field element `n` times - fn square_n(&self, mut n: u32) -> FieldElement { + fn square_n(&self) -> FieldElement { let mut result = self.square(); // Decrease value by 1 since we just did a squaring - n -= 1; + let n = N - 1; for _ in 0..n { result = result.square(); @@ -333,25 +333,25 @@ impl FieldElement { l2 = l1 * self; l1 = l2.square(); l2 = l1 * self; - l1 = l2.square_n(3); + l1 = l2.square_n::<3>(); l0 = l2 * l1; - l1 = l0.square_n(3); + l1 = l0.square_n::<3>(); l0 = l2 * l1; - l2 = l0.square_n(9); + l2 = l0.square_n::<9>(); l1 = l0 * l2; l0 = l1 * l1; l2 = l0 * self; - l0 = l2.square_n(18); + l0 = l2.square_n::<18>(); l2 = l1 * l0; - l0 = l2.square_n(37); + l0 = l2.square_n::<37>(); l1 = l2 * l0; - l0 = l1.square_n(37); + l0 = l1.square_n::<37>(); l1 = l2 * l0; - l0 = l1.square_n(111); + l0 = l1.square_n::<111>(); l2 = l1 * l0; l0 = l2.square(); l1 = l0 * self; - l0 = l1.square_n(223); + l0 = l1.square_n::<223>(); l1 = l2 * l0; l2 = l1.square(); l0 = l2 * self; From b6c3619b7bb1262dda8249d8f5dfc5ecec36ef29 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sat, 19 Jul 2025 10:34:34 +0200 Subject: [PATCH 5/9] Simplify `FieldElement::square_n()` and protect against zero --- ed448-goldilocks/src/field/element.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ed448-goldilocks/src/field/element.rs b/ed448-goldilocks/src/field/element.rs index ee17406e9..39dd3dc89 100644 --- a/ed448-goldilocks/src/field/element.rs +++ b/ed448-goldilocks/src/field/element.rs @@ -277,12 +277,9 @@ impl FieldElement { /// Squares a field element `n` times fn square_n(&self) -> FieldElement { - let mut result = self.square(); + let mut result = *self; - // Decrease value by 1 since we just did a squaring - let n = N - 1; - - for _ in 0..n { + for _ in 0..N { result = result.square(); } From f1d52958b249861884931bfae16b5468b7dcb336 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Fri, 11 Jul 2025 11:45:53 +0200 Subject: [PATCH 6/9] Use double optimization where appropriate --- ed448-goldilocks/src/curve/twedwards/extended.rs | 2 +- ed448-goldilocks/src/curve/twedwards/extensible.rs | 2 +- ed448-goldilocks/src/decaf/points.rs | 2 +- ed448-goldilocks/src/edwards/extended.rs | 2 +- ed448-goldilocks/src/field/element.rs | 4 ++-- ed448-goldilocks/src/field/scalar.rs | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ed448-goldilocks/src/curve/twedwards/extended.rs b/ed448-goldilocks/src/curve/twedwards/extended.rs index 3b80966f0..609c391b0 100644 --- a/ed448-goldilocks/src/curve/twedwards/extended.rs +++ b/ed448-goldilocks/src/curve/twedwards/extended.rs @@ -115,7 +115,7 @@ impl ExtendedPoint { // Compute x let xy = x * y; - let x_numerator = xy + xy; + let x_numerator = xy.double(); let x_denom = y.square() - (a * x.square()); let new_x = x_numerator * x_denom.invert(); diff --git a/ed448-goldilocks/src/curve/twedwards/extensible.rs b/ed448-goldilocks/src/curve/twedwards/extensible.rs index 73f3678df..ff3dc2d07 100644 --- a/ed448-goldilocks/src/curve/twedwards/extensible.rs +++ b/ed448-goldilocks/src/curve/twedwards/extensible.rs @@ -52,7 +52,7 @@ impl ExtensiblePoint { pub fn double(&self) -> ExtensiblePoint { let A = self.X.square(); let B = self.Y.square(); - let C = self.Z.square() + self.Z.square(); + let C = self.Z.square().double(); let D = -A; let E = (self.X + self.Y).square() - A - B; let G = D + B; diff --git a/ed448-goldilocks/src/decaf/points.rs b/ed448-goldilocks/src/decaf/points.rs index d9ab1318e..552ee0efb 100644 --- a/ed448-goldilocks/src/decaf/points.rs +++ b/ed448-goldilocks/src/decaf/points.rs @@ -550,7 +550,7 @@ impl CompressedDecaf { let (I, ok) = (v * u1_sqr).inverse_square_root(); let Dx = I * u1; - let Dxs = (s + s) * Dx; + let Dxs = s.double() * Dx; let mut X = (Dxs * I) * v; let k = Dxs * FieldElement::DECAF_FACTOR; diff --git a/ed448-goldilocks/src/edwards/extended.rs b/ed448-goldilocks/src/edwards/extended.rs index 104d35eb7..d63652e42 100644 --- a/ed448-goldilocks/src/edwards/extended.rs +++ b/ed448-goldilocks/src/edwards/extended.rs @@ -673,7 +673,7 @@ impl EdwardsPoint { // Compute x let xy = x * y; - let x_numerator = xy + xy; + let x_numerator = xy.double(); let x_denom = y.square() - (a * x.square()); let new_x = x_numerator * x_denom.invert(); diff --git a/ed448-goldilocks/src/field/element.rs b/ed448-goldilocks/src/field/element.rs index 39dd3dc89..f458d60b3 100644 --- a/ed448-goldilocks/src/field/element.rs +++ b/ed448-goldilocks/src/field/element.rs @@ -317,7 +317,7 @@ impl FieldElement { } pub fn double(&self) -> Self { - Self(self.0.add(&self.0)) + Self(self.0.double()) } /// Computes the inverse square root of a field element @@ -426,7 +426,7 @@ impl FieldElement { let b = b - Self::ONE; let c = a.square(); - let a = a + a; + let a = a.double(); let e = c + Self::ONE; let T = a * e; let X = a * b; diff --git a/ed448-goldilocks/src/field/scalar.rs b/ed448-goldilocks/src/field/scalar.rs index 2d0dc3179..b18996321 100644 --- a/ed448-goldilocks/src/field/scalar.rs +++ b/ed448-goldilocks/src/field/scalar.rs @@ -314,7 +314,7 @@ impl Field for Scalar { } fn double(&self) -> Self { - self + self + self.double() } fn invert(&self) -> CtOption { @@ -641,7 +641,7 @@ impl Scalar { /// Compute `self` + `self` mod ℓ pub const fn double(&self) -> Self { - self.addition(self) + Self::new(self.scalar.double_mod(&ORDER)) } /// Compute `self` - `rhs` mod ℓ From 0910712dcb07ba2b1be25c128984613f993b6ab2 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sun, 20 Jul 2025 15:07:18 +0200 Subject: [PATCH 7/9] Use `Uint::is_odd()` directly --- ed448-goldilocks/src/field/element.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ed448-goldilocks/src/field/element.rs b/ed448-goldilocks/src/field/element.rs index f458d60b3..94ac5dead 100644 --- a/ed448-goldilocks/src/field/element.rs +++ b/ed448-goldilocks/src/field/element.rs @@ -9,7 +9,7 @@ use crate::{ use elliptic_curve::{ array::Array, bigint::{ - NonZero, U448, U704, + Integer, NonZero, U448, U704, consts::{U56, U84, U88}, }, group::cofactor::CofactorGroup, @@ -258,8 +258,7 @@ impl FieldElement { pub const ZERO: Self = Self(ConstMontyType::new(&U448::ZERO)); pub fn is_negative(&self) -> Choice { - let bytes = self.to_bytes(); - (bytes[0] & 1).into() + self.0.retrieve().is_odd() } /// Inverts a field element From 5a5c671e7c8f02414b63f04e2c72acececcd8c55 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sun, 20 Jul 2025 15:39:41 +0200 Subject: [PATCH 8/9] Hide `EDWARDS_BASEPOINT_ORDER` --- ed448-goldilocks/src/constants.rs | 6 ------ ed448-goldilocks/src/edwards/extended.rs | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/ed448-goldilocks/src/constants.rs b/ed448-goldilocks/src/constants.rs index adb98c281..bd6cc7ebe 100644 --- a/ed448-goldilocks/src/constants.rs +++ b/ed448-goldilocks/src/constants.rs @@ -6,9 +6,3 @@ pub const DECAF_BASEPOINT: DecafPoint = DecafPoint(curve::twedwards::extended::E Z: TWISTED_EDWARDS_BASE_POINT.Z, T: TWISTED_EDWARDS_BASE_POINT.T, }); - -/// `BASEPOINT_ORDER` is the order of the Ed448 basepoint, i.e., -/// $$ -/// \ell = 2^\{446\} + 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d. -/// $$ -pub const EDWARDS_BASEPOINT_ORDER: EdwardsScalar = EdwardsScalar::new(ORDER); diff --git a/ed448-goldilocks/src/edwards/extended.rs b/ed448-goldilocks/src/edwards/extended.rs index d63652e42..cf9e9239b 100644 --- a/ed448-goldilocks/src/edwards/extended.rs +++ b/ed448-goldilocks/src/edwards/extended.rs @@ -3,7 +3,6 @@ use core::fmt::{Display, Formatter, LowerHex, Result as FmtResult, UpperHex}; use core::iter::Sum; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use crate::constants::EDWARDS_BASEPOINT_ORDER; use crate::curve::scalar_mul::variable_base; use crate::curve::twedwards::extended::ExtendedPoint as TwistedExtendedPoint; use crate::field::FieldElement; @@ -724,7 +723,7 @@ impl EdwardsPoint { /// * `false` if `self` has a nonzero torsion component and is not /// in the prime-order subgroup. pub fn is_torsion_free(&self) -> Choice { - (self * EDWARDS_BASEPOINT_ORDER).ct_eq(&Self::IDENTITY) + (self * EdwardsScalar::new(ORDER)).ct_eq(&Self::IDENTITY) } /// Hash a message to a point on the curve From 3a5b1003d85a1c281b001d541e917c241111663f Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sun, 20 Jul 2025 15:48:37 +0200 Subject: [PATCH 9/9] Use squaring instead of multiplication where appropriate --- ed448-goldilocks/src/field/element.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ed448-goldilocks/src/field/element.rs b/ed448-goldilocks/src/field/element.rs index 94ac5dead..2a1d9d59b 100644 --- a/ed448-goldilocks/src/field/element.rs +++ b/ed448-goldilocks/src/field/element.rs @@ -335,7 +335,7 @@ impl FieldElement { l0 = l2 * l1; l2 = l0.square_n::<9>(); l1 = l0 * l2; - l0 = l1 * l1; + l0 = l1.square(); l2 = l0 * self; l0 = l2.square_n::<18>(); l2 = l1 * l0;