1111#![ no_std]
1212#![ deny( missing_docs) ]
1313#![ doc( html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png" ) ]
14- #![ doc( html_root_url = "https://docs.rs/subtle/2.5 .0" ) ]
14+ #![ doc( html_root_url = "https://docs.rs/subtle/2.6 .0" ) ]
1515
1616//! # subtle [](https://crates.io/crates/subtle) [](https://doc.dalek.rs/subtle) [](https://travis-ci.org/dalek-cryptography/subtle)
1717//!
2222//! type is a wrapper around a `u8` that holds a `0` or `1`.
2323//!
2424//! ```toml
25- //! subtle = "2.5 "
25+ //! subtle = "2.6 "
2626//! ```
2727//!
2828//! This crate represents a “best-effort” attempt, since side-channels
4141//! inner `u8` by passing it through a volatile read. For more information, see
4242//! the _About_ section below.
4343//!
44- //! Rust versions from 1.66 or higher support a new best-effort optimization
45- //! barrier ([`core::hint::black_box`]). To use the new optimization barrier,
46- //! enable the `core_hint_black_box` feature.
47- //!
4844//! Rust versions from 1.51 or higher have const generics support. You may enable
4945//! `const-generics` feautre to have `subtle` traits implemented for arrays `[T; N]`.
5046//!
7470//! based on Tim Maclean's [work on `rust-timing-shield`][rust-timing-shield],
7571//! which attempts to provide a more comprehensive approach for preventing
7672//! software side-channels in Rust code.
77- //!
7873//! From version `2.2`, it was based on Diane Hosfelt and Amber Sprenkels' work on
79- //! "Secret Types in Rust". Version `2.5` adds the `core_hint_black_box` feature,
80- //! which uses the original method through the [`core::hint::black_box`] function
81- //! from the Rust standard library.
74+ //! "Secret Types in Rust".
8275//!
8376//! `subtle` is authored by isis agora lovecruft and Henry de Valence.
8477//!
9386//! **USE AT YOUR OWN RISK**
9487//!
9588//! [docs]: https://docs.rs/subtle
96- //! [`core::hint::black_box`]: https://doc.rust-lang.org/core/hint/fn.black_box.html
9789//! [rust-timing-shield]: https://www.chosenplaintext.ca/open-source/rust-timing-shield/security
9890
9991#[ cfg( feature = "std" ) ]
@@ -104,6 +96,9 @@ use core::cmp;
10496use core:: ops:: { BitAnd , BitAndAssign , BitOr , BitOrAssign , BitXor , BitXorAssign , Neg , Not } ;
10597use core:: option:: Option ;
10698
99+ #[ cfg( feature = "core_hint_black_box" ) ]
100+ use core:: hint:: black_box;
101+
107102/// The `Choice` struct represents a choice for use in conditional assignment.
108103///
109104/// It is a wrapper around a `u8`, which should have the value either `1` (true)
@@ -224,36 +219,26 @@ impl Not for Choice {
224219/// Note: Rust's notion of "volatile" is subject to change over time. While this
225220/// code may break in a non-destructive way in the future, “constant-time” code
226221/// is a continually moving target, and this is better than doing nothing.
227- #[ cfg( not( feature = "core_hint_black_box" ) ) ]
228222#[ inline( never) ]
229- fn black_box ( input : u8 ) -> u8 {
230- debug_assert ! ( ( input == 0u8 ) | ( input == 1u8 ) ) ;
231-
223+ fn black_box < T : Copy > ( input : T ) -> T {
232224 unsafe {
233225 // Optimization barrier
234226 //
235- // Unsafe is ok, because:
236- // - &input is not NULL;
237- // - size of input is not zero;
238- // - u8 is neither Sync, nor Send;
239- // - u8 is Copy, so input is always live;
240- // - u8 type is always properly aligned.
241- core:: ptr:: read_volatile ( & input as * const u8 )
227+ // SAFETY:
228+ // - &input is not NULL because we own input;
229+ // - input is Copy and always live;
230+ // - input is always properly aligned.
231+ core:: ptr:: read_volatile ( & input)
242232 }
243233}
244234
245- #[ cfg( feature = "core_hint_black_box" ) ]
246- #[ inline( never) ]
247- fn black_box ( input : u8 ) -> u8 {
248- debug_assert ! ( ( input == 0u8 ) | ( input == 1u8 ) ) ;
249- core:: hint:: black_box ( input)
250- }
251-
252235impl From < u8 > for Choice {
253236 #[ inline]
254237 fn from ( input : u8 ) -> Choice {
238+ debug_assert ! ( ( input == 0u8 ) | ( input == 1u8 ) ) ;
239+
255240 // Our goal is to prevent the compiler from inferring that the value held inside the
256- // resulting `Choice` struct is really an `i1 ` instead of an `i8 `.
241+ // resulting `Choice` struct is really a `bool ` instead of a `u8 `.
257242 Choice ( black_box ( input) )
258243 }
259244}
@@ -270,6 +255,9 @@ impl From<u8> for Choice {
270255/// assert_eq!(x.ct_eq(&y).unwrap_u8(), 0);
271256/// assert_eq!(x.ct_eq(&x).unwrap_u8(), 1);
272257/// ```
258+ //
259+ // #[inline] is specified on these function prototypes to signify that they
260+ #[ allow( unused_attributes) ] // should be in the actual implementation
273261pub trait ConstantTimeEq {
274262 /// Determine if two items are equal.
275263 ///
@@ -280,6 +268,7 @@ pub trait ConstantTimeEq {
280268 /// * `Choice(1u8)` if `self == other`;
281269 /// * `Choice(0u8)` if `self != other`.
282270 #[ inline]
271+ #[ allow( unused_attributes) ]
283272 fn ct_eq ( & self , other : & Self ) -> Choice ;
284273
285274 /// Determine if two items are NOT equal.
@@ -397,6 +386,9 @@ impl ConstantTimeEq for cmp::Ordering {
397386///
398387/// This trait also provides generic implementations of conditional
399388/// assignment and conditional swaps.
389+ //
390+ // #[inline] is specified on these function prototypes to signify that they
391+ #[ allow( unused_attributes) ] // should be in the actual implementation
400392pub trait ConditionallySelectable : Copy {
401393 /// Select `a` or `b` according to `choice`.
402394 ///
@@ -423,6 +415,7 @@ pub trait ConditionallySelectable: Copy {
423415 /// # }
424416 /// ```
425417 #[ inline]
418+ #[ allow( unused_attributes) ]
426419 fn conditional_select ( a : & Self , b : & Self , choice : Choice ) -> Self ;
427420
428421 /// Conditionally assign `other` to `self`, according to `choice`.
@@ -604,12 +597,16 @@ where
604597/// A generic implementation of `ConditionallyNegatable` is provided
605598/// for types `T` which are `ConditionallySelectable` and have `Neg`
606599/// implemented on `&T`.
600+ //
601+ // #[inline] is specified on these function prototypes to signify that they
602+ #[ allow( unused_attributes) ] // should be in the actual implementation
607603pub trait ConditionallyNegatable {
608604 /// Negate `self` if `choice == Choice(1)`; otherwise, leave it
609605 /// unchanged.
610606 ///
611607 /// This function should execute in constant time.
612608 #[ inline]
609+ #[ allow( unused_attributes) ]
613610 fn conditional_negate ( & mut self , choice : Choice ) ;
614611}
615612
@@ -801,6 +798,22 @@ impl<T> CtOption<T> {
801798
802799 Self :: conditional_select ( & self , & f, is_none)
803800 }
801+
802+ /// Convert the `CtOption<T>` wrapper into an `Option<T>`, depending on whether
803+ /// the underlying `is_some` `Choice` was a `0` or a `1` once unwrapped.
804+ ///
805+ /// # Note
806+ ///
807+ /// This function exists to avoid ending up with ugly, verbose and/or bad handled
808+ /// conversions from the `CtOption<T>` wraps to an `Option<T>` or `Result<T, E>`.
809+ /// This implementation doesn't intend to be constant-time nor try to protect the
810+ /// leakage of the `T` since the `Option<T>` will do it anyways.
811+ ///
812+ /// It's equivalent to the corresponding `From` impl, however this version is
813+ /// friendlier for type inference.
814+ pub fn into_option ( self ) -> Option < T > {
815+ self . into ( )
816+ }
804817}
805818
806819impl < T : ConditionallySelectable > ConditionallySelectable for CtOption < T > {
@@ -974,3 +987,21 @@ impl ConstantTimeLess for cmp::Ordering {
974987 ( a as u8 ) . ct_lt ( & ( b as u8 ) )
975988 }
976989}
990+
991+ /// Wrapper type which implements an optimization barrier for all accesses.
992+ #[ derive( Clone , Copy , Debug ) ]
993+ pub struct BlackBox < T : Copy > ( T ) ;
994+
995+ impl < T : Copy > BlackBox < T > {
996+ /// Constructs a new instance of `BlackBox` which will wrap the specified value.
997+ ///
998+ /// All access to the inner value will be mediated by a `black_box` optimization barrier.
999+ pub const fn new ( value : T ) -> Self {
1000+ Self ( value)
1001+ }
1002+
1003+ /// Read the inner value, applying an optimization barrier on access.
1004+ pub fn get ( self ) -> T {
1005+ black_box ( self . 0 )
1006+ }
1007+ }
0 commit comments