krypteia-silentops 0.2.0

Side-channel countermeasure toolkit: constant-time primitives, dudect-style timing leakage verifier, and shared SCA helpers for the krypteia workspace.
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Cédric Mesnil <cslashm@pm.me>

//! Constant-time cryptographic primitives with architecture-specific
//! assembly backends.
//!
//! This module provides the fundamental constant-time operations
//! needed by both classical and post-quantum cryptographic
//! implementations:
//!
//! | Primitive | Operation |
//! |-----------|-----------|
//! | [`ct_select_u8`] | Conditional byte selection without branching |
//! | [`ct_select_i16`] | Conditional i16 selection (NTT coefficients) |
//! | [`ct_select_i32`] | Conditional i32 selection (ML-DSA coefficients) |
//! | [`ct_select_bytes`] | Conditional slice select into a fresh destination |
//! | [`ct_eq`] | Constant-time byte-slice equality comparison |
//! | [`ct_eq_u32`] | Constant-time `u32` equality comparison |
//! | [`ct_zeroize`] | Secure memory zeroization (resists DSE) |
//! | [`ct_zeroize_i16`] | Secure zeroization of i16 slices (coefficients) |
//! | [`ct_copy`] | Conditional buffer copy |
//!
//! # Architecture dispatch
//!
//! At compile time, the crate selects the best implementation:
//!
//! | Target (core) | Method | Instructions used |
//! |---------------|--------|-------------------|
//! | `aarch64` + `asm-aarch64` | Inline asm | `csel`, `csinv` |
//! | `thumbv7*` (M3/M4/M7) + `asm-thumbv7` | Inline asm | IT blocks + conditional exec |
//! | `thumbv8m.main` (M33) + `asm-thumbv7` | Inline asm | IT blocks + conditional exec |
//! | `thumbv6m` (M0/M0+) + `asm-thumbv6m` | Inline asm | AND/OR/XOR (no IT, no csel) |
//! | `thumbv8m.base` (M23) + `asm-thumbv6m` | Inline asm | AND/OR/XOR (no IT, no csel) |
//! | `riscv32` + `asm-riscv32` | Inline asm | AND/OR/XOR (no cmov) |
//! | *(default)* | Pure Rust | Bitwise ops (relies on compiler) |
//!
//! The IT-block (Thumb-2) vs 2-operand (Thumb-1) split on ARM M-profile
//! cores is not driven by `target_feature` — rustc emits no `thumb2`
//! feature for bare-metal M-profile targets, and `target_has_atomic` is
//! set on the M23 (`thumbv8m.base`) core that has no IT blocks. Instead,
//! `silentops/build.rs` derives a `ct_thumb2` cfg from the target triple
//! (true for `thumbv7*` and `thumbv8m.main`, false for `thumbv6m` and
//! `thumbv8m.base`), and the ARM backend gates below select `thumbv7.rs`
//! vs `thumbv6m.rs` on it. See `build.rs` for the rationale.

// Architecture-specific modules
#[cfg(all(target_arch = "x86_64", feature = "asm-x86_64"))]
mod x86_64;
#[cfg(all(target_arch = "x86_64", feature = "asm-x86_64"))]
pub use x86_64::*;

#[cfg(all(target_arch = "aarch64", feature = "asm-aarch64"))]
mod aarch64;
#[cfg(all(target_arch = "aarch64", feature = "asm-aarch64"))]
pub use aarch64::*;

// `ct_thumb2` is emitted by `build.rs` for Thumb-2 / IT-block M-profile cores
// (ARMv7-M, ARMv8-M.main). rustc emits no `target_feature = "thumb2"` for these
// targets, so the triple is the only reliable discriminator — see build.rs. The
// two ARM gates below are disjoint by construction (`ct_thumb2` vs its
// negation), so at most one ARM backend ever compiles.
#[cfg(all(target_arch = "arm", ct_thumb2, feature = "asm-thumbv7"))]
mod thumbv7;
#[cfg(all(target_arch = "arm", ct_thumb2, feature = "asm-thumbv7"))]
pub use thumbv7::*;

#[cfg(all(target_arch = "arm", not(ct_thumb2), feature = "asm-thumbv6m"))]
mod thumbv6m;
#[cfg(all(target_arch = "arm", not(ct_thumb2), feature = "asm-thumbv6m"))]
pub use thumbv6m::*;

#[cfg(all(target_arch = "riscv32", feature = "asm-riscv32"))]
mod riscv32;
#[cfg(all(target_arch = "riscv32", feature = "asm-riscv32"))]
pub use riscv32::*;

// Default: pure Rust fallback (used on desktop without asm-x86_64, or when
// no asm feature enabled at all).
#[cfg(not(any(
    all(target_arch = "x86_64", feature = "asm-x86_64"),
    all(target_arch = "aarch64", feature = "asm-aarch64"),
    all(target_arch = "arm", ct_thumb2, feature = "asm-thumbv7"),
    all(target_arch = "arm", not(ct_thumb2), feature = "asm-thumbv6m"),
    all(target_arch = "riscv32", feature = "asm-riscv32"),
)))]
mod generic;
#[cfg(not(any(
    all(target_arch = "x86_64", feature = "asm-x86_64"),
    all(target_arch = "aarch64", feature = "asm-aarch64"),
    all(target_arch = "arm", ct_thumb2, feature = "asm-thumbv7"),
    all(target_arch = "arm", not(ct_thumb2), feature = "asm-thumbv6m"),
    all(target_arch = "riscv32", feature = "asm-riscv32"),
)))]
pub use generic::*;

#[cfg(test)]
mod tests;