Skip to content

Commit 369e746

Browse files
committed
Merge branch 'release/2.6' into main
2 parents 6b6a81a + 1da93bf commit 369e746

File tree

7 files changed

+138
-83
lines changed

7 files changed

+138
-83
lines changed

.github/workflows/test.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
on: [push, pull_request]
2+
3+
name: Test
4+
5+
jobs:
6+
test:
7+
name: cargo test
8+
runs-on: ubuntu-latest
9+
strategy:
10+
matrix:
11+
rust:
12+
- stable
13+
- beta
14+
- nightly
15+
- 1.41.0
16+
steps:
17+
- name: checkout
18+
uses: actions/checkout@v2
19+
- name: toolchain
20+
uses: actions-rs/toolchain@v1
21+
with:
22+
profile: minimal
23+
toolchain: ${{ matrix.rust }}
24+
target: thumbv7em-none-eabi
25+
override: true
26+
- name: test
27+
uses: actions-rs/cargo@v1
28+
with:
29+
command: test
30+
- name: nightly
31+
uses: actions-rs/cargo@v1
32+
with:
33+
command: test
34+
args: --features nightly
35+
- name: no-default-features
36+
uses: actions-rs/cargo@v1
37+
with:
38+
command: test
39+
args: --no-default-features
40+
- name: std
41+
uses: actions-rs/cargo@v1
42+
with:
43+
command: test
44+
args: --no-default-features --features std
45+
- name: std const-generics
46+
uses: actions-rs/cargo@v1
47+
with:
48+
command: test
49+
args: --no-default-features --features "std const-generics"
50+
- name: std i128
51+
uses: actions-rs/cargo@v1
52+
with:
53+
command: test
54+
args: --no-default-features --features "std i128"
55+
- name: std i128 const-generics
56+
uses: actions-rs/cargo@v1
57+
with:
58+
command: test
59+
args: --no-default-features --features "std i128 const-generics"
60+
- name: no std build
61+
uses: actions-rs/cargo@v1
62+
with:
63+
command: build
64+
args: --no-default-features --target thumbv7em-none-eabi

.travis.yml

Lines changed: 0 additions & 41 deletions
This file was deleted.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ name = "subtle"
55
# - update html_root_url
66
# - update README if necessary by semver
77
# - if any updates were made to the README, also update the module documentation in src/lib.rs
8-
version = "2.5.0"
8+
version = "2.6.0"
99
edition = "2018"
1010
authors = ["Isis Lovecruft <[email protected]>",
1111
"Henry de Valence <[email protected]>"]
@@ -30,6 +30,7 @@ rand = { version = "0.8" }
3030

3131
[features]
3232
const-generics = []
33+
# DEPRECATED: As of 2.5.1, this feature does nothing.
3334
core_hint_black_box = []
3435
default = ["std", "i128"]
3536
std = []

LICENSE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Copyright (c) 2016-2017 Isis Agora Lovecruft, Henry de Valence. All rights reserved.
2+
Copyright (c) 2016-2024 Isis Agora Lovecruft. All rights reserved.
23

34
Redistribution and use in source and binary forms, with or without
45
modification, are permitted provided that the following conditions are

README.md

Lines changed: 2 additions & 10 deletions
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.5"
10+
subtle = "2.6"
1111
```
1212

1313
This crate represents a “best-effort” attempt, since side-channels
@@ -26,10 +26,6 @@ prevent this refinement, the crate tries to hide the value of a `Choice`'s
2626
inner `u8` by passing it through a volatile read. For more information, see
2727
the _About_ section below.
2828

29-
Rust versions from 1.66 or higher support a new best-effort optimization
30-
barrier ([`core::hint::black_box`]). To use the new optimization barrier,
31-
enable the `core_hint_black_box` feature.
32-
3329
Rust versions from 1.51 or higher have const generics support. You may enable
3430
`const-generics` feautre to have `subtle` traits implemented for arrays `[T; N]`.
3531

@@ -59,11 +55,8 @@ Old versions of the optimization barrier in `impl From<u8> for Choice` were
5955
based on Tim Maclean's [work on `rust-timing-shield`][rust-timing-shield],
6056
which attempts to provide a more comprehensive approach for preventing
6157
software side-channels in Rust code.
62-
6358
From version `2.2`, it was based on Diane Hosfelt and Amber Sprenkels' work on
64-
"Secret Types in Rust". Version `2.5` adds the `core_hint_black_box` feature,
65-
which uses the original method through the [`core::hint::black_box`] function
66-
from the Rust standard library.
59+
"Secret Types in Rust".
6760

6861
`subtle` is authored by isis agora lovecruft and Henry de Valence.
6962

@@ -78,5 +71,4 @@ effort is fundamentally limited.
7871
**USE AT YOUR OWN RISK**
7972

8073
[docs]: https://docs.rs/subtle
81-
[`core::hint::black_box`]: https://doc.rust-lang.org/core/hint/fn.black_box.html
8274
[rust-timing-shield]: https://www.chosenplaintext.ca/open-source/rust-timing-shield/security

src/lib.rs

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
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://img.shields.io/crates/v/subtle.svg)](https://crates.io/crates/subtle) [![](https://img.shields.io/badge/dynamic/json.svg?label=docs&uri=https%3A%2F%2Fcrates.io%2Fapi%2Fv1%2Fcrates%2Fsubtle%2Fversions&query=%24.versions%5B0%5D.num&colorB=4F74A6)](https://doc.dalek.rs/subtle) [![](https://travis-ci.org/dalek-cryptography/subtle.svg?branch=master)](https://travis-ci.org/dalek-cryptography/subtle)
1717
//!
@@ -22,7 +22,7 @@
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
@@ -41,10 +41,6 @@
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
//!
@@ -74,11 +70,8 @@
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
//!
@@ -93,7 +86,6 @@
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;
10496
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Neg, Not};
10597
use 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-
252235
impl 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
273261
pub 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
400392
pub 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
607603
pub 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

806819
impl<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+
}

tests/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ macro_rules! generate_integer_conditional_select_tests {
5858
let x: $t = 0; // all 0 bits
5959
let y: $t = !0; // all 1 bits
6060

61-
assert_eq!(<$t>::conditional_select(&x, &y, 0.into()), 0);
61+
assert_eq!(<$t>::conditional_select(&x, &y, 0.into()), x);
6262
assert_eq!(<$t>::conditional_select(&x, &y, 1.into()), y);
6363

6464
let mut z = x;
@@ -423,3 +423,10 @@ fn less_than_ordering() {
423423
assert_eq!(cmp::Ordering::Greater.ct_lt(&cmp::Ordering::Less).unwrap_u8(), 0);
424424
assert_eq!(cmp::Ordering::Less.ct_lt(&cmp::Ordering::Greater).unwrap_u8(), 1);
425425
}
426+
427+
#[test]
428+
fn black_box_round_trip() {
429+
let n = 42u64;
430+
let black_box = BlackBox::new(n);
431+
assert_eq!(n, black_box.get());
432+
}

0 commit comments

Comments
 (0)