diff --git a/ctutils/src/choice.rs b/ctutils/src/choice.rs
index ffc9f505..4417ae4a 100644
--- a/ctutils/src/choice.rs
+++ b/ctutils/src/choice.rs
@@ -45,61 +45,8 @@ impl Choice {
/// Equivalent of [`true`].
pub const TRUE: Self = Self(1);
- /// Convert `Choice` into a `bool`.
- ///
- ///
- /// Security Warning
- ///
- /// Using this function will introduce timing variability, since computing this at all currently
- /// requires a branch.
- ///
- /// This is intended to be used as either the one and only branch at the end of a constant-time
- /// operation to e.g. differentiate between success and failure, or in contexts where
- /// constant-time doesn't matter, e.g. variable-time code that operates on "maybe secret" types
- /// which aren't secrets in a particular context.
- ///
- /// If you are trying to use this in the context of a constant-time operation, be warned that
- /// 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
- pub 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
- pub 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.
- ///
- /// This does not apply `black_box` to the output.
- ///
- ///
- /// 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
- pub const fn to_bool_vartime(self) -> bool {
- self.0 != 0
- }
-
- /// HACK: 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
- pub const fn to_u8_vartime(self) -> u8 {
- self.0
- }
-
//
- // Bitwise ops
+ // `const fn` bitwise ops
//
/// Apply an `and` conditional to the given [`Choice`]s.
@@ -128,7 +75,7 @@ impl Choice {
}
//
- // Comparison ops
+ // `const fn` comparison ops
//
/// `const fn` equality operation.
@@ -355,6 +302,83 @@ impl Choice {
a ^ (self.to_u128_mask() & (a ^ b))
}
+ //
+ // Output conversion methods
+ //
+
+ /// Convert `Choice` into a `bool`.
+ ///
+ ///
+ /// Security Warning
+ ///
+ /// Using this function will introduce timing variability, since computing this at all currently
+ /// requires a branch.
+ ///
+ /// This is intended to be used as either the one and only branch at the end of a constant-time
+ /// operation to e.g. differentiate between success and failure, or in contexts where
+ /// constant-time doesn't matter, e.g. variable-time code that operates on "maybe secret" types
+ /// which aren't secrets in a particular context.
+ ///
+ /// If you are trying to use this in the context of a constant-time operation, be warned that
+ /// 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
+ pub 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
+ pub 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.
+ ///
+ /// This does not apply `black_box` to the output.
+ ///
+ ///
+ /// 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
+ pub const fn to_bool_vartime(self) -> bool {
+ self.0 != 0
+ }
+
+ /// HACK: 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
+ pub const fn to_u8_vartime(self) -> u8 {
+ self.0
+ }
+
+ /// Create a `u8` bitmask.
+ ///
+ /// # Returns
+ /// - `0` for `Choice::FALSE`
+ /// - `u8::MAX` for `Choice::TRUE`
+ #[inline]
+ pub const fn to_u8_mask(self) -> u8 {
+ self.0.wrapping_neg()
+ }
+
+ /// Create a `u16` bitmask.
+ ///
+ /// # Returns
+ /// - `0` for `Choice::FALSE`
+ /// - `u16::MAX` for `Choice::TRUE`
+ #[inline]
+ pub const fn to_u16_mask(self) -> u16 {
+ (self.0 as u16).wrapping_neg()
+ }
+
/// Create a `u32` bitmask.
///
/// # Returns
@@ -362,7 +386,7 @@ impl Choice {
/// - `u32::MAX` for `Choice::TRUE`
#[inline]
pub const fn to_u32_mask(self) -> u32 {
- (self.0 as u32 & 1).wrapping_neg()
+ (self.0 as u32).wrapping_neg()
}
/// Create a `u64` bitmask.
@@ -372,7 +396,7 @@ impl Choice {
/// - `u64::MAX` for `Choice::TRUE`
#[inline]
pub const fn to_u64_mask(self) -> u64 {
- (self.0 as u64 & 1).wrapping_neg()
+ (self.0 as u64).wrapping_neg()
}
/// Create a `u128` bitmask.
@@ -382,7 +406,7 @@ impl Choice {
/// - `u128::MAX` for `Choice::TRUE`
#[inline]
pub const fn to_u128_mask(self) -> u128 {
- (self.0 as u128 & 1).wrapping_neg()
+ (self.0 as u128).wrapping_neg()
}
}
@@ -553,18 +577,6 @@ mod tests {
assert_eq!(a.ct_select(&b, Choice::TRUE).to_bool(), b.to_bool());
}
- #[test]
- fn to_bool() {
- assert!(!Choice::FALSE.to_bool());
- assert!(Choice::TRUE.to_bool());
- }
-
- #[test]
- fn to_u8() {
- assert_eq!(Choice::FALSE.to_u8(), 0);
- assert_eq!(Choice::TRUE.to_u8(), 1);
- }
-
#[test]
fn and() {
assert_eq!((Choice::FALSE & Choice::FALSE).to_u8(), 0);
@@ -813,4 +825,46 @@ mod tests {
assert_eq!(Choice::TRUE.select_u128(a, b), b);
assert_eq!(Choice::FALSE.select_u128(a, b), a);
}
+
+ #[test]
+ fn to_bool() {
+ assert!(!Choice::FALSE.to_bool());
+ assert!(Choice::TRUE.to_bool());
+ }
+
+ #[test]
+ fn to_u8() {
+ assert_eq!(Choice::FALSE.to_u8(), 0);
+ assert_eq!(Choice::TRUE.to_u8(), 1);
+ }
+
+ #[test]
+ fn to_u8_mask() {
+ assert_eq!(Choice::FALSE.to_u8_mask(), 0);
+ assert_eq!(Choice::TRUE.to_u8_mask(), u8::MAX);
+ }
+
+ #[test]
+ fn to_u16_mask() {
+ assert_eq!(Choice::FALSE.to_u16_mask(), 0);
+ assert_eq!(Choice::TRUE.to_u16_mask(), u16::MAX);
+ }
+
+ #[test]
+ fn to_u32_mask() {
+ assert_eq!(Choice::FALSE.to_u32_mask(), 0);
+ assert_eq!(Choice::TRUE.to_u32_mask(), u32::MAX);
+ }
+
+ #[test]
+ fn to_u64_mask() {
+ assert_eq!(Choice::FALSE.to_u64_mask(), 0);
+ assert_eq!(Choice::TRUE.to_u64_mask(), u64::MAX);
+ }
+
+ #[test]
+ fn to_u128_mask() {
+ assert_eq!(Choice::FALSE.to_u128_mask(), 0);
+ assert_eq!(Choice::TRUE.to_u128_mask(), u128::MAX);
+ }
}