fixed_bigint/personality.rs
1//! Personality typestate for [`FixedUInt`](crate::FixedUInt).
2//!
3//! The personality is a zero-size marker generic on [`FixedUInt`] that selects
4//! which implementations of operation primitives are picked at
5//! monomorphization. Two personalities ship with the crate:
6//!
7//! - [`Nct`] (default): standard "non-constant-time" implementation.
8//! - [`Ct`]: constant-time implementation. Slower bodies whose timing is
9//! independent of operand values, defensible against an adversarial
10//! optimizer. Used by signing paths and any code handling secret values.
11//!
12//! ## Const-eval dispatch via `match P::TAG`
13//!
14//! Composite `const fn` methods that need to dispatch on personality can
15//! `match` on the [`PersonalityTag`] associated constant:
16//!
17//! ```ignore
18//! const fn dispatched<P: Personality>(x: u32) -> u32 {
19//! match P::TAG {
20//! PersonalityTag::Nct => fast_body(x),
21//! PersonalityTag::Ct => ct_body(x),
22//! }
23//! }
24//! ```
25//!
26//! Trait *method* calls (e.g. `P::widening_mul(x, y)`) require unstable
27//! `const_trait_impl` in const contexts and are not used by this crate. Tag
28//! dispatch works on stable today and composes through multi-level generic
29//! `const fn` chains without loss of const-eval.
30
31use core::marker::PhantomData;
32
33mod sealed {
34 pub trait Sealed {}
35}
36
37/// Marker trait for personalities. Sealed — implementations live in this
38/// crate. Downstream code uses the [`Nct`] and [`Ct`] types directly or
39/// writes `match P::TAG` dispatch using [`PersonalityTag`].
40pub trait Personality: sealed::Sealed + Copy + 'static {
41 /// Compile-time tag used by `const fn` dispatch:
42 /// `match P::TAG { PersonalityTag::Nct => …, PersonalityTag::Ct => … }`.
43 const TAG: PersonalityTag;
44}
45
46/// Compile-time tag identifying the active personality. Returned by
47/// [`Personality::TAG`] and used as the discriminant for `match P::TAG`
48/// dispatch in `const fn` bodies.
49#[derive(Copy, Clone, PartialEq, Eq, Debug)]
50pub enum PersonalityTag {
51 /// Non-constant-time.
52 Nct,
53 /// Constant-time. Defensible against optimizer-introduced timing leaks.
54 Ct,
55}
56
57/// Non-constant-time marker. Default personality for [`FixedUInt`].
58#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
59pub struct Nct;
60impl sealed::Sealed for Nct {}
61impl Personality for Nct {
62 const TAG: PersonalityTag = PersonalityTag::Nct;
63}
64
65/// Constant-time marker.
66///
67/// Selects constant-time implementations of operation primitives — bodies
68/// whose execution time and memory access pattern do not depend on operand
69/// values. Appropriate for code that handles secret values (signing,
70/// scalar multiplication on secret scalars, Montgomery multiplication on
71/// secret operands).
72///
73/// Calls to `subtle::ConditionallySelectable`, `ConstantTimeEq`, and
74/// related traits are only available for [`FixedUInt`]<_, _, Ct>` — wrong-
75/// variant calls become compile errors, not silent NCT execution.
76///
77/// [`FixedUInt`]: crate::FixedUInt
78#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
79pub struct Ct;
80impl sealed::Sealed for Ct {}
81impl Personality for Ct {
82 const TAG: PersonalityTag = PersonalityTag::Ct;
83}
84
85/// PhantomData helper for storing a personality marker as a zero-size field.
86/// Use as `_p: PersonalityMarker<P>` in struct definitions.
87pub type PersonalityMarker<P> = PhantomData<fn() -> P>;