Skip to content

Commit

Permalink
Merge branch 'release/2.6' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
isislovecruft committed Jun 19, 2024
2 parents 6b6a81a + 1da93bf commit 369e746
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 83 deletions.
64 changes: 64 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
on: [push, pull_request]

name: Test

jobs:
test:
name: cargo test
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- stable
- beta
- nightly
- 1.41.0
steps:
- name: checkout
uses: actions/checkout@v2
- name: toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
target: thumbv7em-none-eabi
override: true
- name: test
uses: actions-rs/cargo@v1
with:
command: test
- name: nightly
uses: actions-rs/cargo@v1
with:
command: test
args: --features nightly
- name: no-default-features
uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features
- name: std
uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features --features std
- name: std const-generics
uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features --features "std const-generics"
- name: std i128
uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features --features "std i128"
- name: std i128 const-generics
uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features --features "std i128 const-generics"
- name: no std build
uses: actions-rs/cargo@v1
with:
command: build
args: --no-default-features --target thumbv7em-none-eabi
41 changes: 0 additions & 41 deletions .travis.yml

This file was deleted.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name = "subtle"
# - update html_root_url
# - update README if necessary by semver
# - if any updates were made to the README, also update the module documentation in src/lib.rs
version = "2.5.0"
version = "2.6.0"
edition = "2018"
authors = ["Isis Lovecruft <[email protected]>",
"Henry de Valence <[email protected]>"]
Expand All @@ -30,6 +30,7 @@ rand = { version = "0.8" }

[features]
const-generics = []
# DEPRECATED: As of 2.5.1, this feature does nothing.
core_hint_black_box = []
default = ["std", "i128"]
std = []
Expand Down
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Copyright (c) 2016-2017 Isis Agora Lovecruft, Henry de Valence. All rights reserved.
Copyright (c) 2016-2024 Isis Agora Lovecruft. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
Expand Down
12 changes: 2 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ instead of `bool` which are intended to execute in constant-time. The `Choice`
type is a wrapper around a `u8` that holds a `0` or `1`.

```toml
subtle = "2.5"
subtle = "2.6"
```

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

Rust versions from 1.66 or higher support a new best-effort optimization
barrier ([`core::hint::black_box`]). To use the new optimization barrier,
enable the `core_hint_black_box` feature.

Rust versions from 1.51 or higher have const generics support. You may enable
`const-generics` feautre to have `subtle` traits implemented for arrays `[T; N]`.

Expand Down Expand Up @@ -59,11 +55,8 @@ Old versions of the optimization barrier in `impl From<u8> for Choice` were
based on Tim Maclean's [work on `rust-timing-shield`][rust-timing-shield],
which attempts to provide a more comprehensive approach for preventing
software side-channels in Rust code.

From version `2.2`, it was based on Diane Hosfelt and Amber Sprenkels' work on
"Secret Types in Rust". Version `2.5` adds the `core_hint_black_box` feature,
which uses the original method through the [`core::hint::black_box`] function
from the Rust standard library.
"Secret Types in Rust".

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

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

[docs]: https://docs.rs/subtle
[`core::hint::black_box`]: https://doc.rust-lang.org/core/hint/fn.black_box.html
[rust-timing-shield]: https://www.chosenplaintext.ca/open-source/rust-timing-shield/security
91 changes: 61 additions & 30 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#![no_std]
#![deny(missing_docs)]
#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")]
#![doc(html_root_url = "https://docs.rs/subtle/2.5.0")]
#![doc(html_root_url = "https://docs.rs/subtle/2.6.0")]

//! # 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)
//!
Expand All @@ -22,7 +22,7 @@
//! type is a wrapper around a `u8` that holds a `0` or `1`.
//!
//! ```toml
//! subtle = "2.5"
//! subtle = "2.6"
//! ```
//!
//! This crate represents a “best-effort” attempt, since side-channels
Expand All @@ -41,10 +41,6 @@
//! inner `u8` by passing it through a volatile read. For more information, see
//! the _About_ section below.
//!
//! Rust versions from 1.66 or higher support a new best-effort optimization
//! barrier ([`core::hint::black_box`]). To use the new optimization barrier,
//! enable the `core_hint_black_box` feature.
//!
//! Rust versions from 1.51 or higher have const generics support. You may enable
//! `const-generics` feautre to have `subtle` traits implemented for arrays `[T; N]`.
//!
Expand Down Expand Up @@ -74,11 +70,8 @@
//! based on Tim Maclean's [work on `rust-timing-shield`][rust-timing-shield],
//! which attempts to provide a more comprehensive approach for preventing
//! software side-channels in Rust code.
//!
//! From version `2.2`, it was based on Diane Hosfelt and Amber Sprenkels' work on
//! "Secret Types in Rust". Version `2.5` adds the `core_hint_black_box` feature,
//! which uses the original method through the [`core::hint::black_box`] function
//! from the Rust standard library.
//! "Secret Types in Rust".
//!
//! `subtle` is authored by isis agora lovecruft and Henry de Valence.
//!
Expand All @@ -93,7 +86,6 @@
//! **USE AT YOUR OWN RISK**
//!
//! [docs]: https://docs.rs/subtle
//! [`core::hint::black_box`]: https://doc.rust-lang.org/core/hint/fn.black_box.html
//! [rust-timing-shield]: https://www.chosenplaintext.ca/open-source/rust-timing-shield/security
#[cfg(feature = "std")]
Expand All @@ -104,6 +96,9 @@ use core::cmp;
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Neg, Not};
use core::option::Option;

#[cfg(feature = "core_hint_black_box")]
use core::hint::black_box;

/// The `Choice` struct represents a choice for use in conditional assignment.
///
/// It is a wrapper around a `u8`, which should have the value either `1` (true)
Expand Down Expand Up @@ -224,36 +219,26 @@ impl Not for Choice {
/// Note: Rust's notion of "volatile" is subject to change over time. While this
/// code may break in a non-destructive way in the future, “constant-time” code
/// is a continually moving target, and this is better than doing nothing.
#[cfg(not(feature = "core_hint_black_box"))]
#[inline(never)]
fn black_box(input: u8) -> u8 {
debug_assert!((input == 0u8) | (input == 1u8));

fn black_box<T: Copy>(input: T) -> T {
unsafe {
// Optimization barrier
//
// Unsafe is ok, because:
// - &input is not NULL;
// - size of input is not zero;
// - u8 is neither Sync, nor Send;
// - u8 is Copy, so input is always live;
// - u8 type is always properly aligned.
core::ptr::read_volatile(&input as *const u8)
// SAFETY:
// - &input is not NULL because we own input;
// - input is Copy and always live;
// - input is always properly aligned.
core::ptr::read_volatile(&input)
}
}

#[cfg(feature = "core_hint_black_box")]
#[inline(never)]
fn black_box(input: u8) -> u8 {
debug_assert!((input == 0u8) | (input == 1u8));
core::hint::black_box(input)
}

impl From<u8> for Choice {
#[inline]
fn from(input: u8) -> Choice {
debug_assert!((input == 0u8) | (input == 1u8));

// Our goal is to prevent the compiler from inferring that the value held inside the
// resulting `Choice` struct is really an `i1` instead of an `i8`.
// resulting `Choice` struct is really a `bool` instead of a `u8`.
Choice(black_box(input))
}
}
Expand All @@ -270,6 +255,9 @@ impl From<u8> for Choice {
/// assert_eq!(x.ct_eq(&y).unwrap_u8(), 0);
/// assert_eq!(x.ct_eq(&x).unwrap_u8(), 1);
/// ```
//
// #[inline] is specified on these function prototypes to signify that they
#[allow(unused_attributes)] // should be in the actual implementation
pub trait ConstantTimeEq {
/// Determine if two items are equal.
///
Expand All @@ -280,6 +268,7 @@ pub trait ConstantTimeEq {
/// * `Choice(1u8)` if `self == other`;
/// * `Choice(0u8)` if `self != other`.
#[inline]
#[allow(unused_attributes)]
fn ct_eq(&self, other: &Self) -> Choice;

/// Determine if two items are NOT equal.
Expand Down Expand Up @@ -397,6 +386,9 @@ impl ConstantTimeEq for cmp::Ordering {
///
/// This trait also provides generic implementations of conditional
/// assignment and conditional swaps.
//
// #[inline] is specified on these function prototypes to signify that they
#[allow(unused_attributes)] // should be in the actual implementation
pub trait ConditionallySelectable: Copy {
/// Select `a` or `b` according to `choice`.
///
Expand All @@ -423,6 +415,7 @@ pub trait ConditionallySelectable: Copy {
/// # }
/// ```
#[inline]
#[allow(unused_attributes)]
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self;

/// Conditionally assign `other` to `self`, according to `choice`.
Expand Down Expand Up @@ -604,12 +597,16 @@ where
/// A generic implementation of `ConditionallyNegatable` is provided
/// for types `T` which are `ConditionallySelectable` and have `Neg`
/// implemented on `&T`.
//
// #[inline] is specified on these function prototypes to signify that they
#[allow(unused_attributes)] // should be in the actual implementation
pub trait ConditionallyNegatable {
/// Negate `self` if `choice == Choice(1)`; otherwise, leave it
/// unchanged.
///
/// This function should execute in constant time.
#[inline]
#[allow(unused_attributes)]
fn conditional_negate(&mut self, choice: Choice);
}

Expand Down Expand Up @@ -801,6 +798,22 @@ impl<T> CtOption<T> {

Self::conditional_select(&self, &f, is_none)
}

/// Convert the `CtOption<T>` wrapper into an `Option<T>`, depending on whether
/// the underlying `is_some` `Choice` was a `0` or a `1` once unwrapped.
///
/// # Note
///
/// This function exists to avoid ending up with ugly, 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.
///
/// It's equivalent to the corresponding `From` impl, however this version is
/// friendlier for type inference.
pub fn into_option(self) -> Option<T> {
self.into()
}
}

impl<T: ConditionallySelectable> ConditionallySelectable for CtOption<T> {
Expand Down Expand Up @@ -974,3 +987,21 @@ impl ConstantTimeLess for cmp::Ordering {
(a as u8).ct_lt(&(b as u8))
}
}

/// Wrapper type which implements an optimization barrier for all accesses.
#[derive(Clone, Copy, Debug)]
pub struct BlackBox<T: Copy>(T);

impl<T: Copy> BlackBox<T> {

Check failure on line 995 in src/lib.rs

View workflow job for this annotation

GitHub Actions / cargo test (1.41.0)

trait bounds other than `Sized` on const fn parameters are unstable
/// Constructs a new instance of `BlackBox` which will wrap the specified value.
///
/// All access to the inner value will be mediated by a `black_box` optimization barrier.
pub const fn new(value: T) -> Self {
Self(value)
}

/// Read the inner value, applying an optimization barrier on access.
pub fn get(self) -> T {
black_box(self.0)
}
}
9 changes: 8 additions & 1 deletion tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ macro_rules! generate_integer_conditional_select_tests {
let x: $t = 0; // all 0 bits
let y: $t = !0; // all 1 bits

assert_eq!(<$t>::conditional_select(&x, &y, 0.into()), 0);
assert_eq!(<$t>::conditional_select(&x, &y, 0.into()), x);
assert_eq!(<$t>::conditional_select(&x, &y, 1.into()), y);

let mut z = x;
Expand Down Expand Up @@ -423,3 +423,10 @@ fn less_than_ordering() {
assert_eq!(cmp::Ordering::Greater.ct_lt(&cmp::Ordering::Less).unwrap_u8(), 0);
assert_eq!(cmp::Ordering::Less.ct_lt(&cmp::Ordering::Greater).unwrap_u8(), 1);
}

#[test]
fn black_box_round_trip() {
let n = 42u64;
let black_box = BlackBox::new(n);
assert_eq!(n, black_box.get());
}

0 comments on commit 369e746

Please sign in to comment.