4545//! barrier ([`core::hint::black_box`]). To use the new optimization barrier,
4646//! enable the `core_hint_black_box` feature.
4747//!
48+ //! Rust versions from 1.51 or higher have const generics support. You may enable
49+ //! `const-generics` feautre to have `subtle` traits implemented for arrays `[T; N]`.
50+ //!
4851//! Versions prior to `2.2` recommended use of the `nightly` feature to enable an
4952//! optimization barrier; this is not required in versions `2.2` and above.
5053//!
97100#[ macro_use]
98101extern crate std;
99102
103+ use core:: cmp;
100104use core:: ops:: { BitAnd , BitAndAssign , BitOr , BitOrAssign , BitXor , BitXorAssign , Neg , Not } ;
101105use core:: option:: Option ;
102106
@@ -239,7 +243,7 @@ fn black_box(input: u8) -> u8 {
239243}
240244
241245#[ cfg( feature = "core_hint_black_box" ) ]
242- #[ inline]
246+ #[ inline( never ) ]
243247fn black_box ( input : u8 ) -> u8 {
244248 debug_assert ! ( ( input == 0u8 ) | ( input == 1u8 ) ) ;
245249 core:: hint:: black_box ( input)
@@ -381,6 +385,14 @@ generate_integer_equal!(u64, i64, 64);
381385generate_integer_equal ! ( u128 , i128 , 128 ) ;
382386generate_integer_equal ! ( usize , isize , :: core:: mem:: size_of:: <usize >( ) * 8 ) ;
383387
388+ /// `Ordering` is `#[repr(i8)]` making it possible to leverage `i8::ct_eq`.
389+ impl ConstantTimeEq for cmp:: Ordering {
390+ #[ inline]
391+ fn ct_eq ( & self , other : & Self ) -> Choice {
392+ ( * self as i8 ) . ct_eq ( & ( * other as i8 ) )
393+ }
394+ }
395+
384396/// A type which can be conditionally selected in constant time.
385397///
386398/// This trait also provides generic implementations of conditional
@@ -398,7 +410,6 @@ pub trait ConditionallySelectable: Copy {
398410 /// # Example
399411 ///
400412 /// ```
401- /// # extern crate subtle;
402413 /// use subtle::ConditionallySelectable;
403414 /// #
404415 /// # fn main() {
@@ -421,7 +432,6 @@ pub trait ConditionallySelectable: Copy {
421432 /// # Example
422433 ///
423434 /// ```
424- /// # extern crate subtle;
425435 /// use subtle::ConditionallySelectable;
426436 /// #
427437 /// # fn main() {
@@ -447,7 +457,6 @@ pub trait ConditionallySelectable: Copy {
447457 /// # Example
448458 ///
449459 /// ```
450- /// # extern crate subtle;
451460 /// use subtle::ConditionallySelectable;
452461 /// #
453462 /// # fn main() {
@@ -542,13 +551,52 @@ generate_integer_conditional_select!( u64 i64);
542551#[ cfg( feature = "i128" ) ]
543552generate_integer_conditional_select ! ( u128 i128 ) ;
544553
554+ /// `Ordering` is `#[repr(i8)]` where:
555+ ///
556+ /// - `Less` => -1
557+ /// - `Equal` => 0
558+ /// - `Greater` => 1
559+ ///
560+ /// Given this, it's possible to operate on orderings as if they're integers,
561+ /// which allows leveraging conditional masking for predication.
562+ impl ConditionallySelectable for cmp:: Ordering {
563+ fn conditional_select ( a : & Self , b : & Self , choice : Choice ) -> Self {
564+ let a = * a as i8 ;
565+ let b = * b as i8 ;
566+ let ret = i8:: conditional_select ( & a, & b, choice) ;
567+
568+ // SAFETY: `Ordering` is `#[repr(i8)]` and `ret` has been assigned to
569+ // a value which was originally a valid `Ordering` then cast to `i8`
570+ unsafe { * ( ( & ret as * const _ ) as * const cmp:: Ordering ) }
571+ }
572+ }
573+
545574impl ConditionallySelectable for Choice {
546575 #[ inline]
547576 fn conditional_select ( a : & Self , b : & Self , choice : Choice ) -> Self {
548577 Choice ( u8:: conditional_select ( & a. 0 , & b. 0 , choice) )
549578 }
550579}
551580
581+ #[ cfg( feature = "const-generics" ) ]
582+ impl < T , const N : usize > ConditionallySelectable for [ T ; N ]
583+ where
584+ T : ConditionallySelectable ,
585+ {
586+ #[ inline]
587+ fn conditional_select ( a : & Self , b : & Self , choice : Choice ) -> Self {
588+ let mut output = * a;
589+ output. conditional_assign ( b, choice) ;
590+ output
591+ }
592+
593+ fn conditional_assign ( & mut self , other : & Self , choice : Choice ) {
594+ for ( a_i, b_i) in self . iter_mut ( ) . zip ( other) {
595+ a_i. conditional_assign ( b_i, choice)
596+ }
597+ }
598+ }
599+
552600/// A type which can be conditionally negated in constant time.
553601///
554602/// # Note
@@ -794,7 +842,6 @@ pub trait ConstantTimeGreater {
794842 /// # Example
795843 ///
796844 /// ```
797- /// # extern crate subtle;
798845 /// use subtle::ConstantTimeGreater;
799846 ///
800847 /// let x: u8 = 13;
@@ -847,7 +894,7 @@ macro_rules! generate_unsigned_integer_greater {
847894 Choice :: from( ( bit & 1 ) as u8 )
848895 }
849896 }
850- }
897+ } ;
851898}
852899
853900generate_unsigned_integer_greater ! ( u8 , 8 ) ;
@@ -857,6 +904,16 @@ generate_unsigned_integer_greater!(u64, 64);
857904#[ cfg( feature = "i128" ) ]
858905generate_unsigned_integer_greater ! ( u128 , 128 ) ;
859906
907+ impl ConstantTimeGreater for cmp:: Ordering {
908+ #[ inline]
909+ fn ct_gt ( & self , other : & Self ) -> Choice {
910+ // No impl of `ConstantTimeGreater` for `i8`, so use `u8`
911+ let a = ( * self as i8 ) + 1 ;
912+ let b = ( * other as i8 ) + 1 ;
913+ ( a as u8 ) . ct_gt ( & ( b as u8 ) )
914+ }
915+ }
916+
860917/// A type which can be compared in some manner and be determined to be less
861918/// than another of the same type.
862919pub trait ConstantTimeLess : ConstantTimeEq + ConstantTimeGreater {
@@ -878,7 +935,6 @@ pub trait ConstantTimeLess: ConstantTimeEq + ConstantTimeGreater {
878935 /// # Example
879936 ///
880937 /// ```
881- /// # extern crate subtle;
882938 /// use subtle::ConstantTimeLess;
883939 ///
884940 /// let x: u8 = 13;
@@ -908,3 +964,13 @@ impl ConstantTimeLess for u32 {}
908964impl ConstantTimeLess for u64 { }
909965#[ cfg( feature = "i128" ) ]
910966impl ConstantTimeLess for u128 { }
967+
968+ impl ConstantTimeLess for cmp:: Ordering {
969+ #[ inline]
970+ fn ct_lt ( & self , other : & Self ) -> Choice {
971+ // No impl of `ConstantTimeLess` for `i8`, so use `u8`
972+ let a = ( * self as i8 ) + 1 ;
973+ let b = ( * other as i8 ) + 1 ;
974+ ( a as u8 ) . ct_lt ( & ( b as u8 ) )
975+ }
976+ }
0 commit comments