141 lines
6.7 KiB
Rust
141 lines
6.7 KiB
Rust
#![no_std]
|
|
#![doc = include_str!("../README.md")]
|
|
#![doc(
|
|
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
|
|
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
|
|
)]
|
|
#![forbid(unsafe_code)] // `unsafe` should go in `cmov`
|
|
#![warn(
|
|
clippy::arithmetic_side_effects,
|
|
clippy::integer_division_remainder_used,
|
|
clippy::panic
|
|
)]
|
|
|
|
//! # API Design
|
|
//!
|
|
//! ## [`Choice`]: constant-time analogue for [`bool`]
|
|
//! Values of this type are one of either [`Choice::FALSE`] or [`Choice::TRUE`].
|
|
//!
|
|
//! To achieve constant-time operation, `Choice` is ultimately used in combination with special
|
|
//! CPU-specific constant-time predication instructions implemented by the [`cmov`] crate
|
|
//! (with a portable "best effort" fallback that cannot provide guarantees).
|
|
//!
|
|
//! It additionally uses various methods to hint to the compiler that it should avoid inserting
|
|
//! branches based on its value where it otherwise would if `bool` were used instead, but cannot
|
|
//! provide guarantees in this regard.
|
|
//!
|
|
//! ## [`CtOption`]: constant-time analogue for [`Option`]
|
|
//! The core `Option` type is typically great for representing the conditional absence or presence
|
|
//! of a value, and provides a number of handy combinators for operating on them.
|
|
//!
|
|
//! However, it has a rather fundamental flaw when constant-time is desirable: its combinators are
|
|
//! lazily evaluated. To ensure constant-time operation, all combinators must be eagerly evaluated
|
|
//! so they aren't conditionally executed based on the value's presence.
|
|
//!
|
|
//! `CtOption` instead carries a `Choice` along with a value, which makes it possible to do
|
|
//! something it isn't with `Option`: evaluate combinators eagerly instead of lazily, running the
|
|
//! same functions regardless of the value's effective presence or absence.
|
|
//!
|
|
//! ## [`CtAssign`]: constant-time additional assignment using [predication]
|
|
//! Support for conditionally assigning to a type or slices thereof (for types which impl the
|
|
//! [`CtAssignSlice`] trait) based on a provided condition value.
|
|
//!
|
|
//! Uses predication instructions or a portable simulation thereof to perform constant-time
|
|
//! conditional assignment based ona [`Choice`].
|
|
//!
|
|
//! *NOTE: for `subtle` users, this trait provides the equivalent of the
|
|
//! `ConditionallySelectable::conditional_assign` method, but as its own trait without a `Sized`
|
|
//! bound so it can also be impl'd for slices*
|
|
//!
|
|
//! ## [`CtEq`]: constant-time analogue for [`PartialEq`]/[`Eq`]
|
|
//! Equality testing often short circuits for performance reasons, but when comparing values in
|
|
//! constant-time such short-circuiting is forbidden.
|
|
//!
|
|
//! The `CtEq` trait is a replacement for these scenarios. It's impl'd for several core types
|
|
//! including unsigned and signed integers as well as slices and arrays. It returns a `Choice`
|
|
//! as opposed to a `bool`], following the standard practice in this crate.
|
|
//!
|
|
//! *NOTE: for `subtle` users, this is the equivalent of the `ConstantTimeEq` trait*
|
|
//!
|
|
//! ## [`CtSelect`]: constant-time [predication]
|
|
//! Predication in computer architecture describes methods for conditionally modifying state
|
|
//! using non-branch instructions which perform conditional modifications based on a *predicate*
|
|
//! or boolean value, in the design of this library a `Choice`.
|
|
//!
|
|
//! The `CtSelect` trait provides methods for performing conditional selection between two
|
|
//! different inputs and returning a new one.
|
|
//!
|
|
//! *NOTE: for `subtle` users, this is the equivalent of the `ConditionallySelectable` trait*
|
|
//!
|
|
//! [predication]: https://en.wikipedia.org/wiki/Predication_(computer_architecture)
|
|
//!
|
|
//! # [`subtle`] interop
|
|
//!
|
|
//! When the `subtle` feature of this crate is enabled, bidirectional [`From`] impls are available
|
|
//! for the following types:
|
|
//!
|
|
//! - [`Choice`] <=> [`subtle::Choice`]
|
|
//! - [`CtOption`] <=> [`subtle::CtOption`]
|
|
//!
|
|
//! 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;
|
|
|
|
mod choice;
|
|
mod ct_option;
|
|
mod traits;
|
|
|
|
pub use choice::Choice;
|
|
pub use ct_option::CtOption;
|
|
pub use traits::{
|
|
ct_assign::{CtAssign, CtAssignSlice},
|
|
ct_eq::{CtEq, CtEqSlice},
|
|
ct_find::CtFind,
|
|
ct_gt::CtGt,
|
|
ct_lookup::CtLookup,
|
|
ct_lt::CtLt,
|
|
ct_neg::CtNeg,
|
|
ct_select::{CtSelect, CtSelectArray, CtSelectUsingCtAssign},
|
|
};
|