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 Dec 14, 2022
1 parent d92ea81 commit 1e4f0d4
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 9 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ required-features = ["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 }

Expand Down
22 changes: 14 additions & 8 deletions src/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,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};

use zeroize::Zeroize;

Expand Down Expand Up @@ -258,9 +256,9 @@ impl Scalar {
/// if `bytes` is a canonical byte representation;
/// - `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::from_bits(bytes);
CtOption::new(candidate, high_bit_unset & candidate.is_canonical())
let candidate = Scalar { bytes };

CtOption::new(candidate, candidate.is_canonical())
}

/// Construct a `Scalar` from the low 255 bits of a 256-bit integer.
Expand Down Expand Up @@ -1138,7 +1136,15 @@ impl Scalar {
/// # }
/// ```
pub 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 1e4f0d4

Please sign in to comment.