diff --git a/Cargo.toml b/Cargo.toml index 5aa97081e..cdb9c5675 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 } diff --git a/src/scalar.rs b/src/scalar.rs index d3be89ccf..5b2f007c4 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -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; @@ -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 { - 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. @@ -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 } }