Skip to content

Commit 728d8d8

Browse files
committed
Merge branch 'release/2.3'
2 parents 1699aa4 + 302f608 commit 728d8d8

File tree

6 files changed

+63
-11
lines changed

6 files changed

+63
-11
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

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
Entries are listed in reverse chronological order.
44

5+
## 2.3.0
6+
7+
* Add `impl ConstantTimeEq for Choice` by @tarcieri.
8+
* Add `impl From<CtOption<T>> for Option<T>` by @CPerezz. This is useful for
9+
handling library code that produces `CtOption`s in contexts where timing
10+
doesn't matter.
11+
* Introduce an MSRV policy.
12+
513
## 2.2.3
614

715
* Remove the `nightly`-only asm-based `black_box` barrier in favor of the

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ name = "subtle"
44
# - update CHANGELOG
55
# - update html_root_url
66
# - update README if necessary by semver
7-
version = "2.2.3"
7+
version = "2.3.0"
88
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
99
"Henry de Valence <hdevalence@hdevalence.ca>"]
1010
readme = "README.md"

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ instead of `bool` which are intended to execute in constant-time. The `Choice`
77
type is a wrapper around a `u8` that holds a `0` or `1`.
88

99
```toml
10-
subtle = "2.2"
10+
subtle = "2.3"
1111
```
1212

1313
This crate represents a “best-effort” attempt, since side-channels
@@ -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: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
1414
#![cfg_attr(feature = "nightly", deny(missing_docs))]
1515
#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")]
16-
#![doc(html_root_url = "https://docs.rs/subtle/2.2.3")]
16+
#![doc(html_root_url = "https://docs.rs/subtle/2.3.0")]
1717

1818
//! Note that docs will only build on nightly Rust until
1919
//! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732).
@@ -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.
@@ -240,6 +241,13 @@ impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
240241
}
241242
}
242243

244+
impl ConstantTimeEq for Choice {
245+
#[inline]
246+
fn ct_eq(&self, rhs: &Choice) -> Choice {
247+
!(*self ^ *rhs)
248+
}
249+
}
250+
243251
/// Given the bit-width `$bit_width` and the corresponding primitive
244252
/// unsigned and signed types `$t_u` and `$t_i` respectively, generate
245253
/// an `ConstantTimeEq` implementation.
@@ -499,6 +507,25 @@ pub struct CtOption<T> {
499507
is_some: Choice,
500508
}
501509

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+
502529
impl<T> CtOption<T> {
503530
/// This method is used to construct a new `CtOption<T>` and takes
504531
/// a value of type `T`, and a `Choice` that determines whether
@@ -507,7 +534,10 @@ impl<T> CtOption<T> {
507534
/// exposed.
508535
#[inline]
509536
pub fn new(value: T, is_some: Choice) -> CtOption<T> {
510-
CtOption { value: value, is_some: is_some }
537+
CtOption {
538+
value: value,
539+
is_some: is_some,
540+
}
511541
}
512542

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

tests/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ fn conditional_select_choice() {
135135
assert_eq!(bool::from(Choice::conditional_select(&f, &t, t)), true);
136136
}
137137

138+
#[test]
139+
fn choice_equal() {
140+
assert!(Choice::from(0).ct_eq(&Choice::from(0)).unwrap_u8() == 1);
141+
assert!(Choice::from(0).ct_eq(&Choice::from(1)).unwrap_u8() == 0);
142+
assert!(Choice::from(1).ct_eq(&Choice::from(0)).unwrap_u8() == 0);
143+
assert!(Choice::from(1).ct_eq(&Choice::from(1)).unwrap_u8() == 1);
144+
}
145+
138146
#[test]
139147
fn test_ctoption() {
140148
let a = CtOption::new(10, Choice::from(1));

0 commit comments

Comments
 (0)