From f7fbc2015c7589f6086124dd52790e92c1eec768 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Fri, 18 Jul 2025 15:59:39 +0200 Subject: [PATCH 1/2] Reuse Edwards windowed scalar multiplication for Decaf --- ed448-goldilocks/src/curve/scalar_mul.rs | 2 -- .../src/curve/scalar_mul/double_and_add.rs | 19 -------------- .../src/curve/scalar_mul/variable_base.rs | 25 ++++++++++++++++--- ed448-goldilocks/src/decaf/ops.rs | 6 ++--- 4 files changed, 25 insertions(+), 27 deletions(-) delete mode 100644 ed448-goldilocks/src/curve/scalar_mul/double_and_add.rs diff --git a/ed448-goldilocks/src/curve/scalar_mul.rs b/ed448-goldilocks/src/curve/scalar_mul.rs index b6ff71a1e..f25bfa715 100644 --- a/ed448-goldilocks/src/curve/scalar_mul.rs +++ b/ed448-goldilocks/src/curve/scalar_mul.rs @@ -1,7 +1,5 @@ -pub(crate) mod double_and_add; // pub(crate) mod double_base; pub(crate) mod variable_base; pub(crate) mod window; -pub(crate) use double_and_add::double_and_add; pub(crate) use variable_base::variable_base; diff --git a/ed448-goldilocks/src/curve/scalar_mul/double_and_add.rs b/ed448-goldilocks/src/curve/scalar_mul/double_and_add.rs deleted file mode 100644 index aac590611..000000000 --- a/ed448-goldilocks/src/curve/scalar_mul/double_and_add.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::curve::twedwards::extended::ExtendedPoint; -use subtle::{Choice, ConditionallySelectable}; - -/// Traditional double and add algorithm -pub(crate) fn double_and_add(point: &ExtendedPoint, s_bits: [bool; 448]) -> ExtendedPoint { - let mut result = ExtendedPoint::IDENTITY; - - // NB, we reverse here, so we are going from MSB to LSB - // XXX: Would be great if subtle had a From for Choice. But maybe that is not it's purpose? - for bit in s_bits.into_iter().rev() { - result = result.double(); - - let mut p = ExtendedPoint::IDENTITY; - p.conditional_assign(point, Choice::from(bit as u8)); - result = result.add(&p); - } - - result -} diff --git a/ed448-goldilocks/src/curve/scalar_mul/variable_base.rs b/ed448-goldilocks/src/curve/scalar_mul/variable_base.rs index bdbca2b79..38b7fe070 100644 --- a/ed448-goldilocks/src/curve/scalar_mul/variable_base.rs +++ b/ed448-goldilocks/src/curve/scalar_mul/variable_base.rs @@ -1,11 +1,12 @@ #![allow(non_snake_case)] use super::window::wnaf::LookupTable; -use crate::EdwardsScalar; +use crate::Scalar; use crate::curve::twedwards::{extended::ExtendedPoint, extensible::ExtensiblePoint}; +use crate::field::CurveWithScalar; use subtle::{Choice, ConditionallyNegatable}; -pub fn variable_base(point: &ExtendedPoint, s: &EdwardsScalar) -> ExtendedPoint { +pub fn variable_base(point: &ExtendedPoint, s: &Scalar) -> ExtendedPoint { let mut result = ExtensiblePoint::IDENTITY; // Recode Scalar @@ -37,12 +38,30 @@ pub fn variable_base(point: &ExtendedPoint, s: &EdwardsScalar) -> ExtendedPoint #[cfg(test)] mod test { use super::*; + use crate::EdwardsScalar; use crate::TWISTED_EDWARDS_BASE_POINT; - use crate::curve::scalar_mul::double_and_add; use elliptic_curve::bigint::U448; + use subtle::ConditionallySelectable; #[test] fn test_scalar_mul() { + /// Traditional double and add algorithm + fn double_and_add(point: &ExtendedPoint, s_bits: [bool; 448]) -> ExtendedPoint { + let mut result = ExtendedPoint::IDENTITY; + + // NB, we reverse here, so we are going from MSB to LSB + // XXX: Would be great if subtle had a From for Choice. But maybe that is not it's purpose? + for bit in s_bits.into_iter().rev() { + result = result.double(); + + let mut p = ExtendedPoint::IDENTITY; + p.conditional_assign(point, Choice::from(bit as u8)); + result = result.add(&p); + } + + result + } + // XXX: In the future use known multiples from Sage in bytes form? let twisted_point = TWISTED_EDWARDS_BASE_POINT; let scalar = EdwardsScalar::new(U448::from_be_hex( diff --git a/ed448-goldilocks/src/decaf/ops.rs b/ed448-goldilocks/src/decaf/ops.rs index 92690c958..ed6a5e16d 100644 --- a/ed448-goldilocks/src/decaf/ops.rs +++ b/ed448-goldilocks/src/decaf/ops.rs @@ -1,4 +1,5 @@ -use crate::{DecafAffinePoint, DecafScalar, curve::scalar_mul::double_and_add}; +use crate::curve::scalar_mul::variable_base; +use crate::{DecafAffinePoint, DecafScalar}; use core::{ borrow::Borrow, iter::Sum, @@ -13,8 +14,7 @@ impl Mul<&DecafScalar> for &DecafPoint { type Output = DecafPoint; fn mul(self, scalar: &DecafScalar) -> DecafPoint { - // XXX: We can do better than double and add - DecafPoint(double_and_add(&self.0, scalar.bits())) + DecafPoint(variable_base(&self.0, scalar)) } } From af3e731fa471632dbca3e0d5d57430ea31005712 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Fri, 18 Jul 2025 16:20:40 +0200 Subject: [PATCH 2/2] Simplify double-and-add code --- ed448-goldilocks/src/curve/scalar_mul/variable_base.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ed448-goldilocks/src/curve/scalar_mul/variable_base.rs b/ed448-goldilocks/src/curve/scalar_mul/variable_base.rs index 38b7fe070..741cc8e08 100644 --- a/ed448-goldilocks/src/curve/scalar_mul/variable_base.rs +++ b/ed448-goldilocks/src/curve/scalar_mul/variable_base.rs @@ -53,10 +53,7 @@ mod test { // XXX: Would be great if subtle had a From for Choice. But maybe that is not it's purpose? for bit in s_bits.into_iter().rev() { result = result.double(); - - let mut p = ExtendedPoint::IDENTITY; - p.conditional_assign(point, Choice::from(bit as u8)); - result = result.add(&p); + result.conditional_assign(&result.add(point), Choice::from(u8::from(bit))); } result