Skip to content

Commit

Permalink
Use a variable time multiplication for the torsion check
Browse files Browse the repository at this point in the history
As the group order is anyway public, there is no reason to prevent
it from leaking to a side channel.
  • Loading branch information
randombit committed Jun 6, 2024
1 parent 56bf398 commit 5a5a768
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 4 deletions.
8 changes: 8 additions & 0 deletions curve25519-dalek/benches/dalek_benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ mod edwards_benches {
});
}

fn is_torsion_free<M: Measurement>(c: &mut BenchmarkGroup<M>) {
let B = &constants::ED25519_BASEPOINT_POINT;
c.bench_function("EdwardsPoint is_torsion_free", move |b| {
b.iter(|| B.is_torsion_free())
});
}

fn consttime_fixed_base_scalar_mul<M: Measurement>(c: &mut BenchmarkGroup<M>) {
let s = Scalar::from(897987897u64).invert();
c.bench_function("Constant-time fixed-base scalar mul", move |b| {
Expand Down Expand Up @@ -62,6 +69,7 @@ mod edwards_benches {

compress(&mut g);
decompress(&mut g);
is_torsion_free(&mut g);
consttime_fixed_base_scalar_mul(&mut g);
consttime_variable_base_scalar_mul(&mut g);
vartime_double_base_scalar_mul(&mut g);
Expand Down
15 changes: 15 additions & 0 deletions curve25519-dalek/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,21 @@ pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint
}
}

/// Perform variable-time, variable-base scalar multiplication.
pub fn vartime_variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint {
match get_selected_backend() {
#[cfg(curve25519_dalek_backend = "simd")]
BackendKind::Avx2 => {
vector::scalar_mul::variable_base::spec_avx2::vartime_mul(point, scalar)
}
#[cfg(all(curve25519_dalek_backend = "simd", nightly))]
BackendKind::Avx512 => {
vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::vartime_mul(point, scalar)
}
BackendKind::Serial => serial::scalar_mul::variable_base::vartime_mul(point, scalar),
}
}

/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
#[allow(non_snake_case)]
pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint {
Expand Down
42 changes: 40 additions & 2 deletions curve25519-dalek/src/backend/serial/scalar_mul/variable_base.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#![allow(non_snake_case)]

use crate::backend::serial::curve_models::ProjectiveNielsPoint;
use core::cmp::Ordering;

use crate::backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint};
use crate::edwards::EdwardsPoint;
use crate::scalar::Scalar;
use crate::traits::Identity;
use crate::window::LookupTable;
use crate::window::{LookupTable, NafLookupTable5};

/// Perform constant-time, variable-base scalar multiplication.
#[rustfmt::skip] // keep alignment of explanatory comments
Expand Down Expand Up @@ -46,3 +48,39 @@ pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint {
}
tmp1.as_extended()
}

/// Perform variable-time, variable-base scalar multiplication.
pub fn vartime_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint {
let naf = scalar.non_adjacent_form(5);
let table = NafLookupTable5::<ProjectiveNielsPoint>::from(point);

// Find starting index
let mut i: usize = 255;
for j in (0..256).rev() {
i = j;
if naf[i] != 0 {
break;
}
}

let mut r = ProjectivePoint::identity();

loop {
let mut t = r.double();

match naf[i].cmp(&0) {
Ordering::Greater => t = &t.as_extended() + &table.select(naf[i] as usize),
Ordering::Less => t = &t.as_extended() - &table.select(-naf[i] as usize),
Ordering::Equal => {}
}

r = t.as_projective();

if i == 0 {
break;
}
i -= 1;
}

r.as_extended()
}
42 changes: 41 additions & 1 deletion curve25519-dalek/src/backend/vector/scalar_mul/variable_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
)]
pub mod spec {

use core::cmp::Ordering;

#[for_target_feature("avx2")]
use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint};

Expand All @@ -15,7 +17,7 @@ pub mod spec {
use crate::edwards::EdwardsPoint;
use crate::scalar::Scalar;
use crate::traits::Identity;
use crate::window::LookupTable;
use crate::window::{LookupTable, NafLookupTable5};

/// Perform constant-time, variable-base scalar multiplication.
pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint {
Expand All @@ -41,4 +43,42 @@ pub mod spec {
}
Q.into()
}

/// Perform variable-time, variable-base scalar multiplication.
pub fn vartime_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint {
let naf = scalar.non_adjacent_form(5);
let table = NafLookupTable5::<CachedPoint>::from(point);

// Find starting index
let mut i: usize = 255;
for j in (0..256).rev() {
i = j;
if naf[i] != 0 {
break;
}
}

let mut Q = ExtendedPoint::identity();

loop {
Q = Q.double();

match naf[i].cmp(&0) {
Ordering::Greater => {
Q = &Q + &table.select(naf[i] as usize);
}
Ordering::Less => {
Q = &Q - &table.select(-naf[i] as usize);
}
Ordering::Equal => {}
}

if i == 0 {
break;
}
i -= 1;
}

Q.into()
}
}
3 changes: 2 additions & 1 deletion curve25519-dalek/src/edwards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,8 @@ impl EdwardsPoint {
/// assert_eq!((P+Q).is_torsion_free(), false);
/// ```
pub fn is_torsion_free(&self) -> bool {
(self * constants::BASEPOINT_ORDER_PRIVATE).is_identity()
crate::backend::vartime_variable_base_mul(self, &constants::BASEPOINT_ORDER_PRIVATE)
.is_identity()
}
}

Expand Down

0 comments on commit 5a5a768

Please sign in to comment.