Skip to content

Commit ececdca

Browse files
implement ConstantTimeLess for slices
1 parent 79a91a3 commit ececdca

File tree

1 file changed

+59
-8
lines changed

1 file changed

+59
-8
lines changed

src/lib.rs

+59-8
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,8 @@ impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
341341
/// Since arrays coerce to slices, this function works with fixed-size arrays:
342342
///
343343
/// ```
344-
/// # use subtle::ConstantTimeEq;
345-
/// #
344+
/// use subtle::ConstantTimeEq;
345+
///
346346
/// let a: [u8; 8] = [0,1,2,3,4,5,6,7];
347347
/// let b: [u8; 8] = [0,1,2,3,0,1,2,3];
348348
///
@@ -359,7 +359,7 @@ impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
359359
// Short-circuit on the *lengths* of the slices, not their
360360
// contents.
361361
if len != _rhs.len() {
362-
return Choice::from(0);
362+
return Choice::of_bool(false);
363363
}
364364

365365
let mut x = IteratedEq::initiate();
@@ -938,7 +938,7 @@ generate_unsigned_integer_greater!(u64, 64);
938938
#[cfg(feature = "i128")]
939939
generate_unsigned_integer_greater!(u128, 128);
940940

941-
impl<T: ConstantTimeGreater + ConstantTimeEq> ConstantTimeGreater for [T] {
941+
impl<T: ConstantTimeGreater> ConstantTimeGreater for [T] {
942942
/// Compare whether one slice of `ConstantTimeGreater` types is greater than another.
943943
///
944944
/// # Note
@@ -953,8 +953,8 @@ impl<T: ConstantTimeGreater + ConstantTimeEq> ConstantTimeGreater for [T] {
953953
/// Since arrays coerce to slices, this function also works with fixed-size arrays:
954954
///
955955
/// ```
956-
/// # use subtle::ConstantTimeGreater;
957-
/// #
956+
/// use subtle::ConstantTimeGreater;
957+
///
958958
/// let a: [u8; 8] = [0,1,2,3,4,5,6,7];
959959
/// let b: [u8; 8] = [0,1,2,3,0,1,2,3];
960960
///
@@ -973,10 +973,10 @@ impl<T: ConstantTimeGreater + ConstantTimeEq> ConstantTimeGreater for [T] {
973973
match len.cmp(&_rhs.len()) {
974974
Ordering::Equal => (),
975975
Ordering::Less => {
976-
return Choice::from(0);
976+
return Choice::of_bool(false);
977977
}
978978
Ordering::Greater => {
979-
return Choice::from(1);
979+
return Choice::of_bool(true);
980980
}
981981
}
982982

@@ -1099,3 +1099,54 @@ impl LexicographicIteratedLess {
10991099
*was_gt |= b.ct_lt(&a);
11001100
}
11011101
}
1102+
1103+
impl<T: ConstantTimeLess> ConstantTimeLess for [T] {
1104+
/// Compare whether one slice of `ConstantTimeLess` types is greater than another.
1105+
///
1106+
/// # Note
1107+
///
1108+
/// This function short-circuits if the lengths of the input slices are different. Otherwise,
1109+
/// it should execute in time independent of the slice contents. When the slice lengths differ,
1110+
/// this implementation applies the [shortlex] ordering scheme, which sorts shorter slices
1111+
/// before longer slices without checking the contents.
1112+
///
1113+
/// [shortlex]: https://en.wikipedia.org/wiki/Shortlex_order
1114+
///
1115+
/// Since arrays coerce to slices, this function also works with fixed-size arrays:
1116+
///
1117+
/// ```
1118+
/// use subtle::ConstantTimeLess;
1119+
///
1120+
/// let a: [u8; 8] = [0,1,2,3,0,1,2,3];
1121+
/// let b: [u8; 8] = [0,1,2,3,4,5,6,7];
1122+
///
1123+
/// let a_lt_a = a.ct_lt(&a);
1124+
/// let a_lt_b = a.ct_lt(&b);
1125+
///
1126+
/// assert_eq!(a_lt_a.unwrap_u8(), 0);
1127+
/// assert_eq!(a_lt_b.unwrap_u8(), 1);
1128+
/// ```
1129+
#[inline]
1130+
fn ct_lt(&self, _rhs: &[T]) -> Choice {
1131+
let len = self.len();
1132+
1133+
// Short-circuit on the *lengths* of the slices, not their contents. Here we apply shortlex
1134+
// ordering, sorting shorter slices before longer ones.
1135+
match len.cmp(&_rhs.len()) {
1136+
Ordering::Equal => (),
1137+
Ordering::Less => {
1138+
return Choice::of_bool(true);
1139+
}
1140+
Ordering::Greater => {
1141+
return Choice::of_bool(false);
1142+
}
1143+
}
1144+
1145+
let mut x = LexicographicIteratedLess::initiate();
1146+
for (ai, bi) in self.iter().zip(_rhs.iter()) {
1147+
x.apply_lt(ai, bi);
1148+
}
1149+
1150+
x.extract_result()
1151+
}
1152+
}

0 commit comments

Comments
 (0)