Skip to content

Commit

Permalink
Optimize the constant time Scalar::is_canonical check
Browse files Browse the repository at this point in the history
  • Loading branch information
elichai committed Jul 27, 2023
1 parent c823543 commit 242b6af
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 8 deletions.
2 changes: 1 addition & 1 deletion curve25519-dalek/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ required-features = ["alloc", "rand_core"]
cfg-if = "1"
rand_core = { version = "0.6.4", default-features = false, optional = true }
digest = { version = "0.10", default-features = false, optional = true }
subtle = { version = "2.3.0", default-features = false }
subtle = { version = "2.4", default-features = false }
serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] }
zeroize = { version = "1", default-features = false, optional = true }

Expand Down
19 changes: 12 additions & 7 deletions curve25519-dalek/src/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,8 @@ use digest::generic_array::typenum::U64;
#[cfg(feature = "digest")]
use digest::Digest;

use subtle::Choice;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq;
use subtle::CtOption;
use subtle::{Choice, CtOption};
use subtle::{ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater};

#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
Expand Down Expand Up @@ -253,9 +251,8 @@ impl Scalar {
/// if `bytes` is a canonical byte representation modulo the group order \\( \ell \\);
/// - `None` if `bytes` is not a canonical byte representation.
pub fn from_canonical_bytes(bytes: [u8; 32]) -> CtOption<Scalar> {
let high_bit_unset = (bytes[31] >> 7).ct_eq(&0);
let candidate = Scalar { bytes };
CtOption::new(candidate, high_bit_unset & candidate.is_canonical())
CtOption::new(candidate, candidate.is_canonical())
}

/// Construct a `Scalar` from the low 255 bits of a 256-bit integer. This breaks the invariant
Expand Down Expand Up @@ -1125,7 +1122,15 @@ impl Scalar {
/// Check whether this `Scalar` is the canonical representative mod \\(\ell\\). This is not
/// public because any `Scalar` that is publicly observed is reduced, by scalar invariant #2.
fn is_canonical(&self) -> Choice {
self.ct_eq(&self.reduce())
let mut over = Choice::from(0);
let mut under = Choice::from(0);
for (this, l) in self.unpack().0.iter().zip(&constants::L.0).rev() {
let gt = this.ct_gt(l);
let eq = this.ct_eq(l);
under |= (!gt & !eq) & !over;
over |= gt;
}
under
}
}

Expand Down

0 comments on commit 242b6af

Please sign in to comment.