From 8142f7314195b43f1f19680c330af200f5e04811 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 5 Oct 2026 12:38:08 -0600 Subject: [PATCH] ctutils: make `Choice::{to_bool, to_u8}` into `const fn`; MSRV 1.86 We have a stable release for MSRV 1.85 users of that version can rely on, and 1.86 was released nearly a year and half ago. We've also received reports of codegen problems in `const fn`s that can only be addressed this way. --- .github/workflows/ctutils.yml | 4 ++-- ctutils/Cargo.toml | 2 +- ctutils/README.md | 2 +- ctutils/src/choice.rs | 22 ++++++++++------------ ctutils/src/ct_option.rs | 8 +++----- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ctutils.yml b/.github/workflows/ctutils.yml index be9a6fb3..b4304da7 100644 --- a/.github/workflows/ctutils.yml +++ b/.github/workflows/ctutils.yml @@ -33,7 +33,7 @@ jobs: strategy: matrix: rust: - - 1.85.0 # MSRV + - 1.86.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -58,7 +58,7 @@ jobs: strategy: matrix: rust: - - 1.85.0 # MSRV + - 1.86.0 # MSRV - stable steps: - uses: actions/checkout@v7 diff --git a/ctutils/Cargo.toml b/ctutils/Cargo.toml index 725866bc..514485a1 100644 --- a/ctutils/Cargo.toml +++ b/ctutils/Cargo.toml @@ -14,7 +14,7 @@ categories = ["cryptography", "no-std"] keywords = ["constant-time", "crypto", "intrinsics"] readme = "README.md" edition = "2024" -rust-version = "1.85" +rust-version = "1.86" [dependencies] cmov = "0.5.3" diff --git a/ctutils/README.md b/ctutils/README.md index 4758a3d8..74cc8d64 100644 --- a/ctutils/README.md +++ b/ctutils/README.md @@ -79,7 +79,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/ctutils/badge.svg [docs-link]: https://docs.rs/ctutils/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[msrv-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg +[msrv-image]: https://img.shields.io/badge/rustc-1.86+-blue.svg [build-image]: https://github.com/RustCrypto/utils/actions/workflows/ctutils.yml/badge.svg [build-link]: https://github.com/RustCrypto/utils/actions/workflows/ctutils.yml [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg diff --git a/ctutils/src/choice.rs b/ctutils/src/choice.rs index f93014d2..16a73879 100644 --- a/ctutils/src/choice.rs +++ b/ctutils/src/choice.rs @@ -386,44 +386,42 @@ impl Choice { /// the small amount of timing variability it introduces can potentially be exploited. Whenever /// possible, prefer fully constant-time approaches instead. /// - // TODO(tarcieri): `const fn` when MSRV 1.86 #[must_use] - pub fn to_bool(self) -> bool { + pub const fn to_bool(self) -> bool { self.to_u8() != 0 } /// Convert [`Choice`] to a `u8`, attempting to apply a "best effort" optimization barrier. - // TODO(tarcieri): `const fn` when MSRV 1.86 #[must_use] - pub fn to_u8(self) -> u8 { + pub const fn to_u8(self) -> u8 { // `black_box` is documented as working on a "best effort" basis. That's fine, this type is // likewise documented as only working on a "best effort" basis itself. The only way we // rely on `black_box` for correctness is it behaving as the identity function. core::hint::black_box(self.0) } - /// HACK: workaround to allow `const fn` boolean support on Rust 1.85. + /// DEPRECATED: previously a workaround to allow `const fn` boolean support on Rust 1.85. /// - /// This does not apply `black_box` to the output. + /// Use [`Choice::to_bool`] instead. /// ///
/// Security Warning /// /// See the security warnings for [`Choice::to_bool`]. ///
- // TODO(tarcieri): deprecate/remove this in favor of `to_bool` when MSRV is Rust 1.86 + #[deprecated(since = "0.4.3", note = "use `Choice::to_bool` instead")] #[must_use] pub const fn to_bool_vartime(self) -> bool { - self.0 != 0 + self.to_bool() } - /// HACK: workaround to allow `const fn` boolean support on Rust 1.85. + /// DEPRECATED: previously a workaround to allow `const fn` boolean support on Rust 1.85. /// - /// This does not apply `black_box` to the output. - // TODO(tarcieri): deprecate/remove this in favor of `to_u8` when MSRV is Rust 1.86 + /// Use [`Choice::to_u8`] instead. + #[deprecated(since = "0.4.3", note = "use `Choice::to_u8` instead")] #[must_use] pub const fn to_u8_vartime(self) -> u8 { - self.0 + self.to_u8() } /// Create a `u8` bitmask. diff --git a/ctutils/src/ct_option.rs b/ctutils/src/ct_option.rs index dcace64b..39a59cf6 100644 --- a/ctutils/src/ct_option.rs +++ b/ctutils/src/ct_option.rs @@ -158,8 +158,7 @@ impl CtOption { #[must_use] #[track_caller] pub const fn expect_ref(&self, msg: &str) -> &T { - // TODO(tarcieri): use `self.is_some().to_bool()` when MSRV is 1.86 - assert!(self.is_some.to_bool_vartime(), "{}", msg); + assert!(self.is_some.to_bool(), "{}", msg); self.as_inner_unchecked() } @@ -222,8 +221,7 @@ impl CtOption { where T: Copy, { - // TODO(tarcieri): use `self.is_some().to_bool()` when MSRV is 1.86 - if self.is_some.to_bool_vartime() { + if self.is_some.to_bool() { Some(self.value) } else { None @@ -693,7 +691,7 @@ mod tests { // Don't actually use this! It's just a test function implemented in variable-time #[allow(clippy::trivially_copy_pass_by_ref)] const fn select_vartime(a: &u8, b: &u8, choice: Choice) -> u8 { - if choice.to_bool_vartime() { *b } else { *a } + if choice.to_bool() { *b } else { *a } } assert_eq!(