From 0dfc57262ad545bada6d255faa4a7655b1cb8245 Mon Sep 17 00:00:00 2001 From: Amber Sprenkels Date: Thu, 5 Jan 2023 11:48:22 +0100 Subject: [PATCH] Add core_hint_black_box feature that uses core::hint::black_box This commit partially reverts the changes from 4978f423, and adds the new optimization barrier implementation under a new feature `core_hint_black_box`. --- .travis.yml | 4 +++- Cargo.toml | 1 + README.md | 20 +++++++++++++++----- src/lib.rs | 38 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index c8b4e17..8f574ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,9 @@ matrix: script: - cargo test && cargo test --no-default-features && cargo test --no-default-features --features std && - cargo test --no-default-features --features "std i128" + cargo test --no-default-features --features "std i128" && + cargo test --no-default-features --features "std core_hint_black_box" && + cargo test --no-default-features --features "std i128 core_hint_black_box" notifications: slack: diff --git a/Cargo.toml b/Cargo.toml index 1c85034..9546c11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ travis-ci = { repository = "dalek-cryptography/subtle", branch = "master"} rand = { version = "0.7" } [features] +core_hint_black_box = [] default = ["std", "i128"] std = [] i128 = [] diff --git a/README.md b/README.md index 32b1fd5..ce0a321 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,10 @@ 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. + Versions prior to `2.2` recommended use of the `nightly` feature to enable an optimization barrier; this is not required in versions `2.2` and above. @@ -40,7 +44,7 @@ Documentation is available [here][docs]. ## Minimum Supported Rust Version -Rust **1.66** or higher. +Rust **1.41** or higher. Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump. @@ -48,10 +52,15 @@ Minimum supported Rust version can be changed in the future, but it will be done This library aims to be the Rust equivalent of Go’s `crypto/subtle` module. -The optimization barrier in `impl From for Choice` was 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. +Old versions of the optimization barrier in `impl From 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.3` adds the `core_hint_black_box` feature, +which uses the original method through the [`core::hint::black_box`] function +from the Rust standard library. `subtle` is authored by isis agora lovecruft and Henry de Valence. @@ -66,4 +75,5 @@ 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 diff --git a/src/lib.rs b/src/lib.rs index ec53e20..4ee9c11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -200,13 +200,47 @@ impl Not for Choice { } } +/// This function is a best-effort attempt to prevent the compiler from knowing +/// anything about the value of the returned `u8`, other than its type. +/// +/// Because we want to support stable Rust, we don't have access to inline +/// assembly or test::black_box, so we use the fact that volatile values will +/// never be elided to register values. +/// +/// 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)); + + 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) + } +} + +#[cfg(feature = "core_hint_black_box")] +#[inline] +fn black_box(input: u8) -> u8 { + debug_assert!((input == 0u8) | (input == 1u8)); + core::hint::black_box(input) +} + impl From 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`. - Choice(core::hint::black_box(input)) + Choice(black_box(input)) } }