Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions curve25519-dalek-derive/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,35 @@ mod inner_spec {
#[for_target_feature("avx2")]
const IS_AVX2: bool = true;

#[for_target_feature("sse2")]
#[test]
fn test_specialized() {
assert!(!IS_AVX2);
}

#[for_target_feature("avx2")]
#[test]
fn test_specialized_avx2() {
assert!(IS_AVX2);
}

#[cfg(test)]
#[for_target_feature("sse2")]
mod tests {
#[test]
fn test_specialized_inner() {
assert!(!super::IS_AVX2);
}
}

#[cfg(test)]
#[for_target_feature("avx2")]
mod tests_avx2 {
#[test]
fn test_specialized_inner_avx2() {
assert!(super::IS_AVX2);
}
}
}

#[unsafe_target_feature("sse2")]
Expand All @@ -127,9 +144,17 @@ fn test_sse2_only() {}
// pretty esoteric feature. Looking at the table of supported avx512 features at
// https://en.wikipedia.org/wiki/AVX-512#CPUs_with_AVX-512 it seems avx512vp2intersect is one of the
// most unusual ones that has rustc knows about
#[cfg(target_feature = "avx512vp2intersect")]
#[unsafe_target_feature("avx512vp2intersect")]
#[test]
fn test_unset_target_feature() {
assert!(std::arch::is_x86_feature_detected!("avx512vp2intersect"));
}

#[cfg(not(target_feature = "avx512vp2intersect"))]
#[unsafe_target_feature("avx512vp2intersect")]
#[test]
fn test_unset_target_feature_removed() {
compile_error!("When an unknown target_feature is set on a test, unsafe_target_feature is expected remove the function");
}

Expand Down
33 changes: 33 additions & 0 deletions curve25519-dalek/benches/dalek_benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,38 @@ mod edwards_benches {
});
}

fn vartime_triple_base_scalar_mul_128<M: Measurement>(c: &mut BenchmarkGroup<M>) {
c.bench_function("Variable-time a1*A1+a2*A2+b*B (128-bit a1,a2)", |bench| {
let mut rng = rng();
let A1 = EdwardsPoint::mul_base(&Scalar::random(&mut rng));
let A2 = EdwardsPoint::mul_base(&Scalar::random(&mut rng));

bench.iter_batched(
|| {
// Generate 128-bit scalars for a1 and a2
let mut a1_bytes = [0u8; 32];
let mut a2_bytes = [0u8; 32];

// Fill lower 16 bytes with random data, upper 16 bytes are zero
for i in 0..16 {
a1_bytes[i] = rng.next_u32() as u8;
a2_bytes[i] = rng.next_u32() as u8;
}

let a1 = Scalar::from_bytes_mod_order(a1_bytes);
let a2 = Scalar::from_bytes_mod_order(a2_bytes);
let b = Scalar::random(&mut rng);

(a1, a2, b)
},
|(a1, a2, b)| {
EdwardsPoint::vartime_triple_scalar_mul_basepoint(&a1, &A1, &a2, &A2, &b)
},
BatchSize::SmallInput,
);
});
}

#[cfg(feature = "digest")]
fn encode_to_curve<M: Measurement>(c: &mut BenchmarkGroup<M>) {
let mut rng = rng();
Expand Down Expand Up @@ -115,6 +147,7 @@ mod edwards_benches {
consttime_fixed_base_scalar_mul(&mut g);
consttime_variable_base_scalar_mul(&mut g);
vartime_double_base_scalar_mul(&mut g);
vartime_triple_base_scalar_mul_128(&mut g);
encode_to_curve(&mut g);
hash_to_curve(&mut g);
}
Expand Down
2 changes: 1 addition & 1 deletion curve25519-dalek/docs/parallel-formulas.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ element vectors, whose optimum choice is determined by the details of
the instruction set. However, it's not possible to perfectly separate
the implementation of the field element vectors from the
implementation of the point operations. Instead, the [`avx2`] and
[`ifma`] backends provide `ExtendedPoint` and `CachedPoint` types, and
`ifma` backends provide `ExtendedPoint` and `CachedPoint` types, and
the [`scalar_mul`] code uses one of the backend types by a type alias.

# Comparison to non-vectorized formulas
Expand Down
28 changes: 28 additions & 0 deletions curve25519-dalek/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,31 @@ pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> Edwa
BackendKind::Serial => serial::scalar_mul::vartime_double_base::mul(a, A, b),
}
}

/// 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 less than \\(2^{128}\\).
#[allow(non_snake_case)]
pub fn vartime_triple_base_mul_128_128_256(
a1: &Scalar,
A1: &EdwardsPoint,
a2: &Scalar,
A2: &EdwardsPoint,
b: &Scalar,
) -> EdwardsPoint {
match get_selected_backend() {
#[cfg(curve25519_dalek_backend = "simd")]
BackendKind::Avx2 => {
vector::scalar_mul::vartime_triple_base::spec_avx2::mul_128_128_256(a1, A1, a2, A2, b)
}
#[cfg(all(curve25519_dalek_backend = "unstable_avx512", nightly))]
BackendKind::Avx512 => {
vector::scalar_mul::vartime_triple_base::spec_avx512ifma_avx512vl::mul_128_128_256(
a1, A1, a2, A2, b,
)
}
BackendKind::Serial => {
serial::scalar_mul::vartime_triple_base::mul_128_128_256(a1, A1, a2, A2, b)
}
}
}
3 changes: 3 additions & 0 deletions curve25519-dalek/src/backend/serial/scalar_mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ pub mod variable_base;
#[allow(missing_docs)]
pub mod vartime_double_base;

#[allow(missing_docs)]
pub mod vartime_triple_base;

#[cfg(feature = "alloc")]
pub mod straus;

Expand Down
Loading