45
45
//! barrier ([`core::hint::black_box`]). To use the new optimization barrier,
46
46
//! enable the `core_hint_black_box` feature.
47
47
//!
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
+ //!
48
51
//! Versions prior to `2.2` recommended use of the `nightly` feature to enable an
49
52
//! optimization barrier; this is not required in versions `2.2` and above.
50
53
//!
97
100
#[ macro_use]
98
101
extern crate std;
99
102
103
+ use core:: cmp;
100
104
use core:: ops:: { BitAnd , BitAndAssign , BitOr , BitOrAssign , BitXor , BitXorAssign , Neg , Not } ;
101
105
use core:: option:: Option ;
102
106
@@ -239,7 +243,7 @@ fn black_box(input: u8) -> u8 {
239
243
}
240
244
241
245
#[ cfg( feature = "core_hint_black_box" ) ]
242
- #[ inline]
246
+ #[ inline( never ) ]
243
247
fn black_box ( input : u8 ) -> u8 {
244
248
debug_assert ! ( ( input == 0u8 ) | ( input == 1u8 ) ) ;
245
249
core:: hint:: black_box ( input)
@@ -381,6 +385,14 @@ generate_integer_equal!(u64, i64, 64);
381
385
generate_integer_equal ! ( u128 , i128 , 128 ) ;
382
386
generate_integer_equal ! ( usize , isize , :: core:: mem:: size_of:: <usize >( ) * 8 ) ;
383
387
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
+
384
396
/// A type which can be conditionally selected in constant time.
385
397
///
386
398
/// This trait also provides generic implementations of conditional
@@ -398,7 +410,6 @@ pub trait ConditionallySelectable: Copy {
398
410
/// # Example
399
411
///
400
412
/// ```
401
- /// # extern crate subtle;
402
413
/// use subtle::ConditionallySelectable;
403
414
/// #
404
415
/// # fn main() {
@@ -421,7 +432,6 @@ pub trait ConditionallySelectable: Copy {
421
432
/// # Example
422
433
///
423
434
/// ```
424
- /// # extern crate subtle;
425
435
/// use subtle::ConditionallySelectable;
426
436
/// #
427
437
/// # fn main() {
@@ -447,7 +457,6 @@ pub trait ConditionallySelectable: Copy {
447
457
/// # Example
448
458
///
449
459
/// ```
450
- /// # extern crate subtle;
451
460
/// use subtle::ConditionallySelectable;
452
461
/// #
453
462
/// # fn main() {
@@ -542,13 +551,52 @@ generate_integer_conditional_select!( u64 i64);
542
551
#[ cfg( feature = "i128" ) ]
543
552
generate_integer_conditional_select ! ( u128 i128 ) ;
544
553
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
+
545
574
impl ConditionallySelectable for Choice {
546
575
#[ inline]
547
576
fn conditional_select ( a : & Self , b : & Self , choice : Choice ) -> Self {
548
577
Choice ( u8:: conditional_select ( & a. 0 , & b. 0 , choice) )
549
578
}
550
579
}
551
580
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
+
552
600
/// A type which can be conditionally negated in constant time.
553
601
///
554
602
/// # Note
@@ -794,7 +842,6 @@ pub trait ConstantTimeGreater {
794
842
/// # Example
795
843
///
796
844
/// ```
797
- /// # extern crate subtle;
798
845
/// use subtle::ConstantTimeGreater;
799
846
///
800
847
/// let x: u8 = 13;
@@ -847,7 +894,7 @@ macro_rules! generate_unsigned_integer_greater {
847
894
Choice :: from( ( bit & 1 ) as u8 )
848
895
}
849
896
}
850
- }
897
+ } ;
851
898
}
852
899
853
900
generate_unsigned_integer_greater ! ( u8 , 8 ) ;
@@ -857,6 +904,16 @@ generate_unsigned_integer_greater!(u64, 64);
857
904
#[ cfg( feature = "i128" ) ]
858
905
generate_unsigned_integer_greater ! ( u128 , 128 ) ;
859
906
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
+
860
917
/// A type which can be compared in some manner and be determined to be less
861
918
/// than another of the same type.
862
919
pub trait ConstantTimeLess : ConstantTimeEq + ConstantTimeGreater {
@@ -878,7 +935,6 @@ pub trait ConstantTimeLess: ConstantTimeEq + ConstantTimeGreater {
878
935
/// # Example
879
936
///
880
937
/// ```
881
- /// # extern crate subtle;
882
938
/// use subtle::ConstantTimeLess;
883
939
///
884
940
/// let x: u8 = 13;
@@ -908,3 +964,13 @@ impl ConstantTimeLess for u32 {}
908
964
impl ConstantTimeLess for u64 { }
909
965
#[ cfg( feature = "i128" ) ]
910
966
impl 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