From d2fab4973c519c88e2f147d3c16e5d0c4eb25c50 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 1 Apr 2026 16:31:23 -0600 Subject: [PATCH] ctutils: add `subtle` migration guide Adds a section to the toplevel documentation to assist users who have existing code which uses `subtle` and would like to migrate to `ctutils`. It covers the mappings of the trait/method names and includes various small caveats that can potentially trip one up. --- ctutils/src/lib.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/ctutils/src/lib.rs b/ctutils/src/lib.rs index f4e159ea..bfa628ed 100644 --- a/ctutils/src/lib.rs +++ b/ctutils/src/lib.rs @@ -79,6 +79,45 @@ //! //! This makes it possible to use `ctutils` in a codebase where other dependencies are using //! `subtle`. +//! +//! # [`subtle`] migration guide +//! +//! This library presents an API which is largely the same shape as `subtle` and amenable to mostly +//! mechanical find-and-replace updates. Using the above `subtle` interop, you can also migrate +//! incrementally by converting `ctutils::Choice` <=> `subtle::Choice` and `ctutils::CtOption` +//! <=> `subtle::CtOption`. +//! +//! The following substitutions can be used to perform the migration: +//! +//! 1. `subtle` => `ctutils` +//! 2. `ConstantTimeEq` => `CtEq`, `ConstantTimeGreater` => `CtGt`, `ConstantTimeLess` => `CtLt`. +//! - These all use the same `ct_eq`/`ct_gt`/`ct_lt` method names as `subtle` with the same type +//! signatures, so only the trait names need to be changed. +//! 3. `ConditionallySelectable` => `CtSelect`, `conditional_select` => `ct_select`. +//! - Note that `ct_select` has a slightly different type signature in that it accepts `&self` +//! as the LHS argument. This needs to be changed in the `impl` blocks, but call sites are +//! compatible if you update the method name alone because it's valid "fully qualified syntax". +//! Changing them from `T::conditional_select(&a, &b, choice)` => `a.ct_select(&b, choice)` +//! may still be nice for brevity. +//! - `conditional_assign` => `CtAssign::ct_assign`: this one will require some manual work as +//! this method has been split out of `ConditionallySelectable` into its own `CtAssign` trait, +//! which makes it possible to impl on DSTs like slices which can't be returned from a select +//! operation because they're `!Sized`. +//! 4. `ConditionallyNegatable` => `CtNeg`, `conditional_negate` => `ct_neg` +//! +//! ## `CtOption` notes +//! +//! A notable semantic change from `subtle` is combinators like `CtOption::map` no longer have a +//! `Default` bound and will call the provided function with the contained value unconditionally. +//! +//! This means whatever value was provided at the time the `CtOption` was constructed now needs to +//! uphold whatever invariants the provided function is expecting. +//! +//! Code which previously constructed a `CtOption` with an invalid inner value that worked with +//! `subtle` because the `Default` value upheld these invariants might break when the provided +//! function is now called with the invalid inner value. +//! +//! See also: [dalek-cryptography/subtle#63](https://github.com/dalek-cryptography/subtle/issues/63) #[cfg(feature = "alloc")] extern crate alloc;