|
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 |
|
@@ -350,6 +351,14 @@ generate_integer_equal!(u64, i64, 64);
|
350 | 351 | generate_integer_equal!(u128, i128, 128);
|
351 | 352 | generate_integer_equal!(usize, isize, ::core::mem::size_of::<usize>() * 8);
|
352 | 353 |
|
| 354 | +/// `Ordering` is `#[repr(i32)] making it possible to leverage `i32::ct_eq`. |
| 355 | +impl ConstantTimeEq for cmp::Ordering { |
| 356 | + #[inline] |
| 357 | + fn ct_eq(&self, other: &Self) -> Choice { |
| 358 | + (*self as i32).ct_eq(&(*other as i32)) |
| 359 | + } |
| 360 | +} |
| 361 | + |
353 | 362 | /// A type which can be conditionally selected in constant time.
|
354 | 363 | ///
|
355 | 364 | /// This trait also provides generic implementations of conditional
|
@@ -511,6 +520,26 @@ generate_integer_conditional_select!( u64 i64);
|
511 | 520 | #[cfg(feature = "i128")]
|
512 | 521 | generate_integer_conditional_select!(u128 i128);
|
513 | 522 |
|
| 523 | +/// `Ordering` is `#[repr(i32)]` where: |
| 524 | +/// |
| 525 | +/// - `Less` => -1 |
| 526 | +/// - `Equal` => 0 |
| 527 | +/// - `Greater` => 1 |
| 528 | +/// |
| 529 | +/// Given this, it's possible to operate on orderings as if they're integers, |
| 530 | +/// which allows leveraging conditional masking for predication. |
| 531 | +impl ConditionallySelectable for cmp::Ordering { |
| 532 | + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { |
| 533 | + let a = *a as i32; |
| 534 | + let b = *b as i32; |
| 535 | + let ret = i32::conditional_select(&a, &b, choice); |
| 536 | + |
| 537 | + // SAFETY: `Ordering` is `#[repr(i32)]` and `ret` has been assigned to |
| 538 | + // a value which was originally a valid `Ordering` then cast to `i32` |
| 539 | + unsafe { *((&ret as *const _) as *const cmp::Ordering) } |
| 540 | + } |
| 541 | +} |
| 542 | + |
514 | 543 | impl ConditionallySelectable for Choice {
|
515 | 544 | #[inline]
|
516 | 545 | fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
@@ -811,6 +840,16 @@ generate_unsigned_integer_greater!(u64, 64);
|
811 | 840 | #[cfg(feature = "i128")]
|
812 | 841 | generate_unsigned_integer_greater!(u128, 128);
|
813 | 842 |
|
| 843 | +impl ConstantTimeGreater for cmp::Ordering { |
| 844 | + #[inline] |
| 845 | + fn ct_gt(&self, other: &Self) -> Choice { |
| 846 | + // No impl of `ConstantTimeGreater` for `i32`, so use `u8` |
| 847 | + let a = (*self as i32) + 1; |
| 848 | + let b = (*other as i32) + 1; |
| 849 | + (a as u8).ct_gt(&(b as u8)) |
| 850 | + } |
| 851 | +} |
| 852 | + |
814 | 853 | /// A type which can be compared in some manner and be determined to be less
|
815 | 854 | /// than another of the same type.
|
816 | 855 | pub trait ConstantTimeLess: ConstantTimeEq + ConstantTimeGreater {
|
@@ -862,3 +901,13 @@ impl ConstantTimeLess for u32 {}
|
862 | 901 | impl ConstantTimeLess for u64 {}
|
863 | 902 | #[cfg(feature = "i128")]
|
864 | 903 | impl ConstantTimeLess for u128 {}
|
| 904 | + |
| 905 | +impl ConstantTimeLess for cmp::Ordering { |
| 906 | + #[inline] |
| 907 | + fn ct_lt(&self, other: &Self) -> Choice { |
| 908 | + // No impl of `ConstantTimeLess` for `i32`, so use `u8` |
| 909 | + let a = (*self as i32) + 1; |
| 910 | + let b = (*other as i32) + 1; |
| 911 | + (a as u8).ct_lt(&(b as u8)) |
| 912 | + } |
| 913 | +} |
0 commit comments