|
87 | 87 | #[macro_use]
|
88 | 88 | extern crate std;
|
89 | 89 |
|
| 90 | +use core::cmp; |
90 | 91 | use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Neg, Not};
|
91 | 92 | use core::option::Option;
|
92 | 93 |
|
@@ -371,6 +372,14 @@ generate_integer_equal!(u64, i64, 64);
|
371 | 372 | generate_integer_equal!(u128, i128, 128);
|
372 | 373 | generate_integer_equal!(usize, isize, ::core::mem::size_of::<usize>() * 8);
|
373 | 374 |
|
| 375 | +/// `Ordering` is `#[repr(i8)]` making it possible to leverage `i8::ct_eq`. |
| 376 | +impl ConstantTimeEq for cmp::Ordering { |
| 377 | + #[inline] |
| 378 | + fn ct_eq(&self, other: &Self) -> Choice { |
| 379 | + (*self as i8).ct_eq(&(*other as i8)) |
| 380 | + } |
| 381 | +} |
| 382 | + |
374 | 383 | /// A type which can be conditionally selected in constant time.
|
375 | 384 | ///
|
376 | 385 | /// This trait also provides generic implementations of conditional
|
@@ -529,6 +538,26 @@ generate_integer_conditional_select!( u64 i64);
|
529 | 538 | #[cfg(feature = "i128")]
|
530 | 539 | generate_integer_conditional_select!(u128 i128);
|
531 | 540 |
|
| 541 | +/// `Ordering` is `#[repr(i8)]` where: |
| 542 | +/// |
| 543 | +/// - `Less` => -1 |
| 544 | +/// - `Equal` => 0 |
| 545 | +/// - `Greater` => 1 |
| 546 | +/// |
| 547 | +/// Given this, it's possible to operate on orderings as if they're integers, |
| 548 | +/// which allows leveraging conditional masking for predication. |
| 549 | +impl ConditionallySelectable for cmp::Ordering { |
| 550 | + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { |
| 551 | + let a = *a as i8; |
| 552 | + let b = *b as i8; |
| 553 | + let ret = i8::conditional_select(&a, &b, choice); |
| 554 | + |
| 555 | + // SAFETY: `Ordering` is `#[repr(i8)]` and `ret` has been assigned to |
| 556 | + // a value which was originally a valid `Ordering` then cast to `i8` |
| 557 | + unsafe { *((&ret as *const _) as *const cmp::Ordering) } |
| 558 | + } |
| 559 | +} |
| 560 | + |
532 | 561 | impl ConditionallySelectable for Choice {
|
533 | 562 | #[inline]
|
534 | 563 | fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
@@ -843,6 +872,16 @@ generate_unsigned_integer_greater!(u64, 64);
|
843 | 872 | #[cfg(feature = "i128")]
|
844 | 873 | generate_unsigned_integer_greater!(u128, 128);
|
845 | 874 |
|
| 875 | +impl ConstantTimeGreater for cmp::Ordering { |
| 876 | + #[inline] |
| 877 | + fn ct_gt(&self, other: &Self) -> Choice { |
| 878 | + // No impl of `ConstantTimeGreater` for `i8`, so use `u8` |
| 879 | + let a = (*self as i8) + 1; |
| 880 | + let b = (*other as i8) + 1; |
| 881 | + (a as u8).ct_gt(&(b as u8)) |
| 882 | + } |
| 883 | +} |
| 884 | + |
846 | 885 | /// A type which can be compared in some manner and be determined to be less
|
847 | 886 | /// than another of the same type.
|
848 | 887 | pub trait ConstantTimeLess: ConstantTimeEq + ConstantTimeGreater {
|
@@ -893,3 +932,13 @@ impl ConstantTimeLess for u32 {}
|
893 | 932 | impl ConstantTimeLess for u64 {}
|
894 | 933 | #[cfg(feature = "i128")]
|
895 | 934 | impl ConstantTimeLess for u128 {}
|
| 935 | + |
| 936 | +impl ConstantTimeLess for cmp::Ordering { |
| 937 | + #[inline] |
| 938 | + fn ct_lt(&self, other: &Self) -> Choice { |
| 939 | + // No impl of `ConstantTimeLess` for `i8`, so use `u8` |
| 940 | + let a = (*self as i8) + 1; |
| 941 | + let b = (*other as i8) + 1; |
| 942 | + (a as u8).ct_lt(&(b as u8)) |
| 943 | + } |
| 944 | +} |
0 commit comments