From ed83542d7e1cbeca43184e8786770d2ec708a73c Mon Sep 17 00:00:00 2001 From: Aaron Feickert <66188213+AaronFeickert@users.noreply.github.com> Date: Sat, 11 Jan 2025 21:57:50 -0600 Subject: [PATCH] curve: add precomputation length to MSM structs (#685) --- curve25519-dalek/src/backend/mod.rs | 26 +++++++++++++++++++ .../serial/scalar_mul/precomputed_straus.rs | 8 ++++++ .../vector/scalar_mul/precomputed_straus.rs | 8 ++++++ curve25519-dalek/src/edwards.rs | 11 ++++++++ curve25519-dalek/src/ristretto.rs | 11 ++++++++ curve25519-dalek/src/traits.rs | 6 +++++ 6 files changed, 70 insertions(+) diff --git a/curve25519-dalek/src/backend/mod.rs b/curve25519-dalek/src/backend/mod.rs index c5fab97..cfb8b00 100644 --- a/curve25519-dalek/src/backend/mod.rs +++ b/curve25519-dalek/src/backend/mod.rs @@ -128,6 +128,32 @@ impl VartimePrecomputedStraus { } } + /// Return the number of static points in the precomputation. + pub fn len(&self) -> usize { + use crate::traits::VartimePrecomputedMultiscalarMul; + + match self { + #[cfg(curve25519_dalek_backend = "simd")] + VartimePrecomputedStraus::Avx2(inner) => inner.len(), + #[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))] + VartimePrecomputedStraus::Avx512ifma(inner) => inner.len(), + VartimePrecomputedStraus::Scalar(inner) => inner.len(), + } + } + + /// Determine if the precomputation is empty. + pub fn is_empty(&self) -> bool { + use crate::traits::VartimePrecomputedMultiscalarMul; + + match self { + #[cfg(curve25519_dalek_backend = "simd")] + VartimePrecomputedStraus::Avx2(inner) => inner.is_empty(), + #[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))] + VartimePrecomputedStraus::Avx512ifma(inner) => inner.is_empty(), + VartimePrecomputedStraus::Scalar(inner) => inner.is_empty(), + } + } + pub fn optional_mixed_multiscalar_mul( &self, static_scalars: I, diff --git a/curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs b/curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs index 53116c6..8c3a474 100644 --- a/curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs +++ b/curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs @@ -46,6 +46,14 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { } } + fn len(&self) -> usize { + self.static_lookup_tables.len() + } + + fn is_empty(&self) -> bool { + self.static_lookup_tables.is_empty() + } + fn optional_mixed_multiscalar_mul( &self, static_scalars: I, diff --git a/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs b/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs index 6038d18..cc44c57 100644 --- a/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs +++ b/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -57,6 +57,14 @@ pub mod spec { } } + fn len(&self) -> usize { + self.static_lookup_tables.len() + } + + fn is_empty(&self) -> bool { + self.static_lookup_tables.is_empty() + } + fn optional_mixed_multiscalar_mul( &self, static_scalars: I, diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index 02f8631..811764b 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -879,6 +879,14 @@ impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation { Self(crate::backend::VartimePrecomputedStraus::new(static_points)) } + fn len(&self) -> usize { + self.0.len() + } + + fn is_empty(&self) -> bool { + self.0.is_empty() + } + fn optional_mixed_multiscalar_mul( &self, static_scalars: I, @@ -2136,6 +2144,9 @@ mod test { let precomputation = VartimeEdwardsPrecomputation::new(static_points.iter()); + assert_eq!(precomputation.len(), 128); + assert!(!precomputation.is_empty()); + let P = precomputation.vartime_mixed_multiscalar_mul( &static_scalars, &dynamic_scalars, diff --git a/curve25519-dalek/src/ristretto.rs b/curve25519-dalek/src/ristretto.rs index 1918d03..49c134e 100644 --- a/curve25519-dalek/src/ristretto.rs +++ b/curve25519-dalek/src/ristretto.rs @@ -1027,6 +1027,14 @@ impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation { )) } + fn len(&self) -> usize { + self.0.len() + } + + fn is_empty(&self) -> bool { + self.0.is_empty() + } + fn optional_mixed_multiscalar_mul( &self, static_scalars: I, @@ -1852,6 +1860,9 @@ mod test { let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter()); + assert_eq!(precomputation.len(), 128); + assert!(!precomputation.is_empty()); + let P = precomputation.vartime_mixed_multiscalar_mul( &static_scalars, &dynamic_scalars, diff --git a/curve25519-dalek/src/traits.rs b/curve25519-dalek/src/traits.rs index ea7ca3b..80a6423 100644 --- a/curve25519-dalek/src/traits.rs +++ b/curve25519-dalek/src/traits.rs @@ -299,6 +299,12 @@ pub trait VartimePrecomputedMultiscalarMul: Sized { I: IntoIterator, I::Item: Borrow; + /// Return the number of static points in the precomputation. + fn len(&self) -> usize; + + /// Determine if the precomputation is empty. + fn is_empty(&self) -> bool; + /// Given `static_scalars`, an iterator of public scalars /// \\(b_i\\), compute /// $$