From 7cca75ad6e239f112583bdec222cbca55f439a42 Mon Sep 17 00:00:00 2001 From: zz-sol Date: Tue, 16 Jun 2026 23:13:07 -0400 Subject: [PATCH] [ed25519] improve docs (#53) * improve docs * more docs * improve docs --- curve25519/README.md | 4 ++- .../serial/scalar_mul/vartime_triple_base.rs | 17 +++++++++--- .../vector/scalar_mul/vartime_triple_base.rs | 26 +++++++++++-------- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/curve25519/README.md b/curve25519/README.md index 7a91e7c..3f80fa4 100644 --- a/curve25519/README.md +++ b/curve25519/README.md @@ -16,7 +16,9 @@ method and a reduced set of well-tested backends. |---|---| | [`solana-ed25519`](./solana-ed25519) | Fork of `curve25519-dalek` with ZIP-215-compliant Ed25519 from `ed25519-zebra`, HEEA-accelerated `verify` / `verify_zebra`, and a narrowed backend set (removed `u32` and constraint device supports). | | [`curve25519-cuda`](./curve25519-cuda) | GPU-accelerated multi-scalar multiplication (MSM) via CUDA/SPPARK. Falls back to CPU when CUDA is unavailable. | -| [`curve25519-derive`](../curve25519-derive) | Helper proc-macro crate (`#[unsafe_target_feature]`) inherited from upstream; required to write clean SIMD code. Identical to the one in dalek 0.5.0 | + +SIMD helper macros come from the workspace dependency `curve25519-dalek-derive = "0.1.1"`; +there is no local `curve25519-derive` crate in this workspace. --- diff --git a/curve25519/solana-ed25519/src/backend/serial/scalar_mul/vartime_triple_base.rs b/curve25519/solana-ed25519/src/backend/serial/scalar_mul/vartime_triple_base.rs index 1eb81a6..35ad9ef 100644 --- a/curve25519/solana-ed25519/src/backend/serial/scalar_mul/vartime_triple_base.rs +++ b/curve25519/solana-ed25519/src/backend/serial/scalar_mul/vartime_triple_base.rs @@ -19,6 +19,15 @@ use crate::scalar::{HEEA_MAX_INDEX, Scalar}; use crate::traits::Identity; use crate::window::NafLookupTable5; +const DYNAMIC_NAF_WINDOW: usize = 5; + +// This intentionally differs from the vector backend when precomputed tables +// are enabled. The serial backend can select width-5 b_lo digits from the +// larger width-8 basepoint table, but keeps the smaller NAF window here as a +// backend-specific performance tradeoff. Revisit this only with comparative +// serial/vector benchmarks. +const B_LO_NAF_WINDOW: usize = DYNAMIC_NAF_WINDOW; + /// Compute \\(a_1 A_1 + a_2 A_2 + b B\\) in variable time, where \\(B\\) is the Ed25519 basepoint. /// /// This function is optimized for the case where \\(a_1\\) and \\(a_2\\) are known to be less than @@ -82,10 +91,10 @@ pub(crate) fn mul_128_128_256_prechecked( // The serial backend keeps b_lo at width 5 even when table_B is the larger // precomputed width-8 basepoint table. The vector backend uses width 8 in // that configuration. - let a1_naf = a1.non_adjacent_form(5); - let a2_naf = a2.non_adjacent_form(5); - let b_lo_naf = b_lo.non_adjacent_form(5); - let b_hi_naf = b_hi.non_adjacent_form(5); + let a1_naf = a1.non_adjacent_form(DYNAMIC_NAF_WINDOW); + let a2_naf = a2.non_adjacent_form(DYNAMIC_NAF_WINDOW); + let b_lo_naf = b_lo.non_adjacent_form(B_LO_NAF_WINDOW); + let b_hi_naf = b_hi.non_adjacent_form(DYNAMIC_NAF_WINDOW); // Find starting index - check all NAFs up to bit 127 // (with potential carry to bit 128 or 129) diff --git a/curve25519/solana-ed25519/src/backend/vector/scalar_mul/vartime_triple_base.rs b/curve25519/solana-ed25519/src/backend/vector/scalar_mul/vartime_triple_base.rs index fd70973..2ab049e 100644 --- a/curve25519/solana-ed25519/src/backend/vector/scalar_mul/vartime_triple_base.rs +++ b/curve25519/solana-ed25519/src/backend/vector/scalar_mul/vartime_triple_base.rs @@ -30,6 +30,17 @@ pub mod spec { use crate::traits::Identity; use crate::window::NafLookupTable5; + const DYNAMIC_NAF_WINDOW: usize = 5; + + // This intentionally differs from the serial backend when precomputed + // tables are enabled. The AVX2 basepoint table is width 8, and this vector + // path uses the larger b_lo NAF window in that configuration as a + // backend-specific performance tradeoff. + #[cfg(feature = "precomputed-tables")] + const B_LO_NAF_WINDOW: usize = 8; + #[cfg(not(feature = "precomputed-tables"))] + const B_LO_NAF_WINDOW: usize = DYNAMIC_NAF_WINDOW; + /// Compute \\(a_1 A_1 + a_2 A_2 + b B\\) in variable time, where \\(B\\) is the Ed25519 basepoint. /// /// This function is optimized for the case where \\(a_1\\) and \\(a_2\\) are known to be less than @@ -91,17 +102,10 @@ pub mod spec { let b_hi = Scalar::from_canonical_bytes_unchecked(b_hi_bytes); // Compute NAF representations (all scalars are now ~128 bits) - let a1_naf = a1.non_adjacent_form(5); - let a2_naf = a2.non_adjacent_form(5); - - // With precomputed tables, the vector backend uses the larger width-8 - // basepoint table for b_lo. The serial backend keeps b_lo at width 5. - #[cfg(feature = "precomputed-tables")] - let b_lo_naf = b_lo.non_adjacent_form(8); - #[cfg(not(feature = "precomputed-tables"))] - let b_lo_naf = b_lo.non_adjacent_form(5); - - let b_hi_naf = b_hi.non_adjacent_form(5); + let a1_naf = a1.non_adjacent_form(DYNAMIC_NAF_WINDOW); + let a2_naf = a2.non_adjacent_form(DYNAMIC_NAF_WINDOW); + let b_lo_naf = b_lo.non_adjacent_form(B_LO_NAF_WINDOW); + let b_hi_naf = b_hi.non_adjacent_form(DYNAMIC_NAF_WINDOW); // Find starting index - check all NAFs up to bit 127 // (with potential carry to bit 128 or 129)