[WIP] ctutils: constant-time selection and equality testing
(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:
- 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 -
black_boxis (rather annoyingly) onlyconst fnin Rust 1.86. This is targeting an initial MSRV of 1.85, as well as supportingconst fnconstructors forChoicewhich are a big missing piece insubtleright 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.
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
So why not just bump the MSRV to 1.86?
@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.
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.
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.