From 1582468b4aeaafb360e7a2d240c421980a36e762 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 May 2020 01:55:44 +1200 Subject: [PATCH] EdwardsPoint::vartime_check_double_scalar_mul_basepoint Checks whether [8a]A + [8b]B = [8]C in variable time. This can be used to implement RFC 8032-compatible Ed25519 signature validation. Note that it includes a multiplication by the cofactor. --- curve25519-dalek/benches/dalek_benchmarks.rs | 19 +++++++++++++++++++ curve25519-dalek/src/backend/mod.rs | 16 ++++++++++++++++ curve25519-dalek/src/edwards.rs | 17 +++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/curve25519-dalek/benches/dalek_benchmarks.rs b/curve25519-dalek/benches/dalek_benchmarks.rs index 62a6280f4..80bc0acc0 100644 --- a/curve25519-dalek/benches/dalek_benchmarks.rs +++ b/curve25519-dalek/benches/dalek_benchmarks.rs @@ -56,6 +56,24 @@ mod edwards_benches { }); } + fn vartime_check_double_scalar_mul_basepoint(c: &mut BenchmarkGroup) { + c.bench_function( + "Variable-time 8(aA+bB)=8C, A&C variable, B fixed", + |bench| { + let mut rng = thread_rng(); + let A = &Scalar::random(&mut rng) * constants::ED25519_BASEPOINT_TABLE; + let C = &Scalar::random(&mut rng) * constants::ED25519_BASEPOINT_TABLE; + bench.iter_batched( + || (Scalar::random(&mut rng), Scalar::random(&mut rng)), + |(a, b)| { + EdwardsPoint::vartime_check_double_scalar_mul_basepoint(&a, &A, &b, &C) + }, + BatchSize::SmallInput, + ); + }, + ); + } + pub(crate) fn edwards_benches() { let mut c = Criterion::default(); let mut g = c.benchmark_group("edwards benches"); @@ -65,6 +83,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_check_double_scalar_mul_basepoint(&mut g); } } diff --git a/curve25519-dalek/src/backend/mod.rs b/curve25519-dalek/src/backend/mod.rs index 9ad1dd3de..5f1ae0487 100644 --- a/curve25519-dalek/src/backend/mod.rs +++ b/curve25519-dalek/src/backend/mod.rs @@ -249,3 +249,19 @@ 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), } } + +/// Checks whether \\([8a]A + [8b]B = [8]C\\) in variable time. +/// +/// This can be used to implement [RFC 8032]-compatible Ed25519 signature validation. +/// Note that it includes a multiplication by the cofactor. +/// +/// [RFC 8032]: https://tools.ietf.org/html/rfc8032 +#[allow(non_snake_case)] +pub(crate) fn scalar_mul_abglsv_pornin( + a: &Scalar, + A: &EdwardsPoint, + b: &Scalar, + C: &EdwardsPoint, +) -> EdwardsPoint { + serial::scalar_mul::abglsv_pornin::mul(a, A, b, C) +} diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index 856fac12f..99c4b6f4a 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -906,6 +906,23 @@ impl EdwardsPoint { ) -> EdwardsPoint { crate::backend::vartime_double_base_mul(a, A, b) } + + /// Checks whether \\([8a]A + [8b]B = [8]C\\) in variable time. + /// + /// This can be used to implement [RFC 8032]-compatible Ed25519 signature validation. + /// Note that it includes a multiplication by the cofactor. + /// + /// [RFC 8032]: https://tools.ietf.org/html/rfc8032 + pub fn vartime_check_double_scalar_mul_basepoint( + a: &Scalar, + A: &EdwardsPoint, + b: &Scalar, + C: &EdwardsPoint, + ) -> bool { + crate::backend::scalar_mul_abglsv_pornin(a, A, b, C) + .mul_by_cofactor() + .is_identity() + } } #[cfg(feature = "precomputed-tables")]