Skip to content

Conversation

@tarcieri
Copy link
Member

@tarcieri tarcieri commented Oct 28, 2025

(for lack of a better name)

This is woefully incomplete but I'm pushing it up anyway since several people have asked about const fn support for subtle

This is effectively a rewrite of subtle using the cmov crate for both constant-time selection/predication as well as equality comparisons. The cmov crate uses architecture-specific predication instructions on x86(_64) and ARM, with a portable "best effort" fallback.

It uses core::hint::black_box on-access as an optimization barrier, however this is a belt-and-suspenders defense paired with the use of intrinsics where available. This is a bit different than subtle which uses a similar black box optimization barrier at initialization time. There are a couple problems with this approach:

  1. The optimizer can assume the value is unchanged after repeat accesses to the same Choice, which means it could potentially insert a branch to e.g. shortcut-on-zero
  2. black_box is (rather annoyingly) only const fn in Rust 1.86. This is targeting an initial MSRV of 1.85 This PR is MSRV 1.87 but we'll have a revertable downgrade to 1.85, as well as supporting const fn constructors for Choice which are a big missing piece in subtle right now

I'm not intending to replace our usages of subtle with this yet (I'd much rather ship everything), but would like to have a testbed for using cmov for constant-time operations which can perhaps inform a potential subtle v3.0 (if I can make that happen).

To be useful, this still needs an equivalent of CtOption (ideally with much more const fn support), which I was hoping to implement before pushing this up. Added!

One thing we could consider is trying to get this complete enough to use in crypto-bigint to replace ConstChoice/ConstCtOption, though it would likely need all of the methods on Choice to be const fn, which would probably involve shipping Choice without black_box (i.e. what crypto-bigint is already doing), and then adding a subtle integration for converting ctutil::Choice -> subtle::Choice and a prospective ctutil::CtOption -> subtle::CtOption.

cc @andrewwhitehead @fjarri @ycscaly

@fjarri
Copy link

fjarri commented Oct 28, 2025

So why not just bump the MSRV to 1.86?

@tarcieri
Copy link
Member Author

tarcieri commented Oct 28, 2025

@fjarri we're trying to ship everything as 1.85 so it can be packaged on Debian stable, then bumping MSRV after that (now that there's an MSRV-aware resolver)


That said, there are several places post-1.85 features would be nice in crypto-bigint, particularly inference for const-generic trait parameters.

@tarcieri tarcieri force-pushed the ctutils branch 8 times, most recently from ab9d02c to 9511556 Compare December 20, 2025 00:26
@tarcieri tarcieri changed the title [WIP] ctutils: constant-time selection and equality testing ctutils: constant-time selection and equality testing Dec 20, 2025
@tarcieri
Copy link
Member Author

Ugh, cast_unsigned was stabilized in 1.87. I might start with that MSRV and then open a PR to downgrade the MSRV back to 1.85 so we can just revert that when we bump MSRV.

Inspired by the `subtle` crate, this is a next-generation constant time
utility crate built on the `cmov` crate's constant-time
selection/predication and equality comparisons, which are exposed as
`CtSelect` and `CtEq` traits (equivalent to `ConditionallySelectable`
and `ConstantTimeEq` in `subtle`).

Additionally, it uses `black_box` as a "best effort" optimization
barrier whenever accessing its constant time conditional type (called
`Choice` as in `subtle`), providing an additional line of defense
against possible future compiler optimizations.

It also has a `CtOption` type like `subtle` which provides a
constant-time equivalent to `Option` but with combinators that are
evaluated eagerly rather than lazily so they behave the same regardless
of the effective absence or presence of the underlying value.

It proactively makes functions `const fn` wherever possible, making it
possible to construct and use `Choice` and `CtOption` in these contexts.

The `Copy` bounds have been removed, making it possible for everything
to be used on heap-allocated types, such as `BoxedUint` in
`crypto-bigint`.

The above two issues taken together are the main reasons why
`crypto-bigint` currently embeds its own mini-`subtle` alike, which it
would be nice to use this library to replace.
@tarcieri tarcieri marked this pull request as ready for review December 20, 2025 00:41
@tarcieri
Copy link
Member Author

I'd like to finally push this one past the draft PR it's been sitting in for ages and land it and iterate on new features/functionality.

I'm going to go ahead and merge but I'd appreciate any retroactive review.

@tarcieri tarcieri merged commit 87d6dd2 into master Dec 20, 2025
109 checks passed
@tarcieri tarcieri deleted the ctutils branch December 20, 2025 00:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants