Skip to content

Commit 1e4f0d4

Browse files
committed
Optimize the constant time Scalar::is_canonical check
1 parent d92ea81 commit 1e4f0d4

File tree

2 files changed

+15
-9
lines changed

2 files changed

+15
-9
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ required-features = ["rand_core"]
5555
cfg-if = "1"
5656
rand_core = { version = "0.6.4", default-features = false, optional = true }
5757
digest = { version = "0.10", default-features = false, optional = true }
58-
subtle = { version = "2.3.0", default-features = false }
58+
subtle = { version = "2.4", default-features = false }
5959
serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] }
6060
zeroize = { version = "1", default-features = false }
6161

src/scalar.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,8 @@ use digest::generic_array::typenum::U64;
160160
#[cfg(feature = "digest")]
161161
use digest::Digest;
162162

163-
use subtle::Choice;
164-
use subtle::ConditionallySelectable;
165-
use subtle::ConstantTimeEq;
166-
use subtle::CtOption;
163+
use subtle::{Choice, CtOption};
164+
use subtle::{ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater};
167165

168166
use zeroize::Zeroize;
169167

@@ -258,9 +256,9 @@ impl Scalar {
258256
/// if `bytes` is a canonical byte representation;
259257
/// - `None` if `bytes` is not a canonical byte representation.
260258
pub fn from_canonical_bytes(bytes: [u8; 32]) -> CtOption<Scalar> {
261-
let high_bit_unset = (bytes[31] >> 7).ct_eq(&0);
262-
let candidate = Scalar::from_bits(bytes);
263-
CtOption::new(candidate, high_bit_unset & candidate.is_canonical())
259+
let candidate = Scalar { bytes };
260+
261+
CtOption::new(candidate, candidate.is_canonical())
264262
}
265263

266264
/// Construct a `Scalar` from the low 255 bits of a 256-bit integer.
@@ -1138,7 +1136,15 @@ impl Scalar {
11381136
/// # }
11391137
/// ```
11401138
pub fn is_canonical(&self) -> Choice {
1141-
self.ct_eq(&self.reduce())
1139+
let mut over = Choice::from(0);
1140+
let mut under = Choice::from(0);
1141+
for (this, l) in self.unpack().0.iter().zip(&constants::L.0).rev() {
1142+
let gt = this.ct_gt(l);
1143+
let eq = this.ct_eq(l);
1144+
under |= (!gt & !eq) & !over;
1145+
over |= gt;
1146+
}
1147+
under
11421148
}
11431149
}
11441150

0 commit comments

Comments
 (0)