Skip to content

Commit 3764f42

Browse files
authored
Implement `From<CtOption<T>> for Option<T> (#75)
* Implement `From<CtOption<T>> for Option<T> As stated in #73 and #74 the `CtOption<T>` API is a bit unflexible when you try to extract the value from the `CtOption` or you want to convert the `CtOption<T>` into an `Option<T>` or a `Result<T>`. Therefore the conversion from `CtOption<T>` to `Option<T>` has been implemented to avoid having situations like: ```rust if ct_opt.is_some() { return ct_opt.unwrap() } else { return Err(....) } ``` # NOTE: This impl is done to avoid ending up with unpractical, verbose and/or bad handled conversions from the `CtOption<T>` wraps to an `Option<T>` or `Result<T, E>`. This implementation doesn't intend to be constant-time nor try to protect the leakage of the `T` since the `Option<T>` will do it anyways. Closes #73 & #74 * Add "std" feature for CtOption conversion * Use core::option::Option instead of std's one * Change Rust version for MSRV test case The code uploaded to solve #73 & #74 includes a feature that was added to the Rust language in Rust_1.41.0 via RFC2451. Therefore, the minimum version needed in order to allow the tests pass for the MSRV testcase is the one mentioned avobe. As suggested per @hdevalence, it might not be worth it to try to support a +4yo version of Rust, so the .travis.yml has been changed in order to update the version used to test the MSRV case to 1.41.0. * Update MSRV policy in README.md
1 parent 2d447a4 commit 3764f42

File tree

3 files changed

+37
-8
lines changed

3 files changed

+37
-8
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ matrix:
1313
env: NAME="nightly feature"
1414
script: cargo test --features nightly
1515
# Test MSRV
16-
- rust: 1.13.0
16+
- rust: 1.41.0
1717
env: NAME="MSRV test"
1818
script: cargo test --no-default-features --features std
1919
# Test if crate can be truly built without std

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ used in release mode.
3838

3939
Documentation is available [here][docs].
4040

41+
## Minimum Supported Rust Version
42+
43+
Rust **1.41** or higher.
44+
45+
Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump.
46+
4147
## About
4248

4349
This library aims to be the Rust equivalent of Go’s `crypto/subtle` module.

src/lib.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,23 @@
2323
extern crate std;
2424

2525
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Neg, Not};
26+
use core::option::Option;
2627

2728
/// The `Choice` struct represents a choice for use in conditional assignment.
28-
///
29+
///
2930
/// It is a wrapper around a `u8`, which should have the value either `1` (true)
3031
/// or `0` (false).
31-
///
32+
///
3233
/// The conversion from `u8` to `Choice` passes the value through an optimization
3334
/// barrier, as a best-effort attempt to prevent the compiler from inferring that
3435
/// the `Choice` value is a boolean. This strategy is based on Tim Maclean's
3536
/// [work on `rust-timing-shield`][rust-timing-shield], which attempts to provide
3637
/// a more comprehensive approach for preventing software side-channels in Rust
3738
/// code.
38-
///
39+
///
3940
/// The `Choice` struct implements operators for AND, OR, XOR, and NOT, to allow
4041
/// combining `Choice` values. These operations do not short-circuit.
41-
///
42+
///
4243
/// [rust-timing-shield]:
4344
/// https://www.chosenplaintext.ca/open-source/rust-timing-shield/security
4445
#[derive(Copy, Clone, Debug)]
@@ -136,11 +137,11 @@ impl Not for Choice {
136137

137138
/// This function is a best-effort attempt to prevent the compiler from knowing
138139
/// anything about the value of the returned `u8`, other than its type.
139-
///
140+
///
140141
/// Because we want to support stable Rust, we don't have access to inline
141142
/// assembly or test::black_box, so we use the fact that volatile values will
142143
/// never be elided to register values.
143-
///
144+
///
144145
/// Note: Rust's notion of "volatile" is subject to change over time. While this
145146
/// code may break in a non-destructive way in the future, “constant-time” code
146147
/// is a continually moving target, and this is better than doing nothing.
@@ -506,6 +507,25 @@ pub struct CtOption<T> {
506507
is_some: Choice,
507508
}
508509

510+
impl<T> From<CtOption<T>> for Option<T> {
511+
/// Convert the `CtOption<T>` wrapper into an `Option<T>`, depending on whether
512+
/// the underlying `is_some` `Choice` was a `0` or a `1` once unwrapped.
513+
///
514+
/// # Note
515+
///
516+
/// This function exists to avoid ending up with ugly, verbose and/or bad handled
517+
/// conversions from the `CtOption<T>` wraps to an `Option<T>` or `Result<T, E>`.
518+
/// This implementation doesn't intend to be constant-time nor try to protect the
519+
/// leakage of the `T` since the `Option<T>` will do it anyways.
520+
fn from(source: CtOption<T>) -> Option<T> {
521+
if source.is_some().unwrap_u8() == 1u8 {
522+
Option::Some(source.value)
523+
} else {
524+
None
525+
}
526+
}
527+
}
528+
509529
impl<T> CtOption<T> {
510530
/// This method is used to construct a new `CtOption<T>` and takes
511531
/// a value of type `T`, and a `Choice` that determines whether
@@ -514,7 +534,10 @@ impl<T> CtOption<T> {
514534
/// exposed.
515535
#[inline]
516536
pub fn new(value: T, is_some: Choice) -> CtOption<T> {
517-
CtOption { value: value, is_some: is_some }
537+
CtOption {
538+
value: value,
539+
is_some: is_some,
540+
}
518541
}
519542

520543
/// This returns the underlying value but panics if it

0 commit comments

Comments
 (0)