subtle
Pure-Rust traits and utilities for writing constant-time cryptographic code that resists timing side-channel attacks.
Repository Health
Technical Analysis
subtle provides a small set of Rust traits and a Choice wrapper type for writing constant-time cryptographic code, i.e. code whose control flow and memory access patterns do not depend on secret values. Where ordinary Rust code compares byte slices or conditionally selects a value with == or if, subtle supplies ConstantTimeEq, ConditionallySelectable, ConditionallyNegatable, ConstantTimeGreater, and ConstantTimeLess implementations that use bitwise operations and an optimization barrier instead of branches, guarding against compiler optimizations that would reintroduce a timing side-channel.
Built no_std by default so it compiles for embedded and constrained targets, subtle is a foundational building block of the dalek-cryptography ecosystem (curve25519-dalek, ed25519-dalek, x25519-dalek) and is depended on by hundreds of other Rust cryptography crates, with over 660 million downloads on crates.io. It positions itself as the Rust equivalent of Go’s crypto/subtle package.
What You Get
- Choice type - a
u8wrapper representing a boolean that has been passed through an optimization barrier to resist compiler branch-reintroduction - ConstantTimeEq trait - constant-time equality (
ct_eq) and inequality (ct_ne) for byte slices,Choice,cmp::Ordering, and more - ConditionallySelectable trait - branchless conditional assignment (
conditional_select,conditional_assign,conditional_swap) for copyable types, including fixed-size arrays via const generics - ConditionallyNegatable trait - constant-time conditional negation for any type implementing
NegandConditionallySelectable - ConstantTimeGreater / ConstantTimeLess traits - constant-time ordering comparisons for unsigned integer types
- CtOption<T> - a constant-time analogue of
Option<T>that avoids branching on presence or absence of a value
Common Use Cases
- MAC/signature verification - comparing computed vs expected authentication tags without leaking timing information about where they first differ
- Elliptic-curve point and scalar arithmetic - conditionally selecting between two curve points or scalars based on a secret bit, as used throughout curve25519-dalek and ed25519-dalek
- Password/key comparison - checking secrets like API keys or password hashes without a data-dependent early-exit comparison
- Embedded/no_std cryptography - building constant-time primitives for microcontrollers and other constrained targets where
stdisn’t available
Under The Hood
Architecture
subtle is deliberately a single ~1,000-line src/lib.rs with no submodules: it defines a Choice newtype wrapping a u8, then a handful of small traits (ConstantTimeEq, ConditionallySelectable, ConditionallyNegatable, ConstantTimeGreater, ConstantTimeLess) plus the CtOption<T> type, each with blanket or per-type trait implementations rather than a class hierarchy. The Choice-to-u8 conversion is routed through a volatile read to act as an optimization barrier, and every trait method is implemented with bitwise AND/OR/XOR/NOT instead of branches so the compiler has no natural place to reintroduce a conditional jump. There is no runtime state, no allocation, and no I/O — the entire architecture is a set of composable, side-effect-free trait implementations, which is the appropriate shape for a primitive this narrow in scope.
Tech Stack
Pure Rust, #![no_std] by default with opt-in std, i128, and const-generics Cargo features (the last enabling trait impls over [T; N]), and a single dev-dependencies entry on rand used only by the test suite. The CI matrix builds and tests against stable, beta, nightly, and the crate’s MSRV of Rust 1.41, runs every feature-flag combination, and cross-compiles to the thumbv7em-none-eabi embedded target to guarantee the no-std build stays intact.
Code Quality
tests/mod.rs carries a couple dozen #[test] functions exercising equality, conditional-select/assign/swap, conditional-negate, ordering comparisons, and CtOption, and a separate fuzz/ directory wires up cargo-fuzz harnesses for property-style fuzzing — notable rigor for a crate whose entire value proposition is subtle correctness bugs. #![deny(missing_docs)] forces every public item to carry rustdoc, and debug_asserts guard invariants in debug builds while staying out of release binaries. There’s no separate lint/format CI step visible, but the multi-toolchain, multi-feature-flag test matrix substitutes for much of what a linter would catch.
API Design
The public surface is intentionally tiny and idiomatic: a handful of traits that mirror standard-library conventions (ct_eq next to PartialEq, CtOption<T> next to Option<T>) so callers already familiar with Rust need almost no ramp-up beyond understanding why constant-time variants exist. Every public item carries rustdoc explaining both usage and the security rationale, and the crate documents explicit caveats (debug-only invariant checks, release-mode intent, hardware-level limits of software timing protection) rather than overselling its guarantees.
Used by 4 apps in this directory
openduck
Databases · Data Engineering
OpenDuck brings MotherDuck-style cloud capabilities to self-hosted DuckDB — attach remote databases, run hybrid queries across local and remote nodes, and own your data with an open gRPC and Arrow IPC protocol.
PostHog
Analytics · Monitoring · Developer Tools
The all-in-one open source product platform combining analytics, session replay, feature flags, error tracking, AI observability, and a built-in data warehouse in a single self-hostable stack.
Vaultwarden
Password Manager · Security
Unofficial Bitwarden-compatible server in Rust — run the full Bitwarden ecosystem on a Raspberry Pi using every official client you already have, without the multi-container overhead.
Vibe Kanban
AI Agents · AI Code Assistants · Project Management
A kanban board for planning work and dispatching Claude Code, Codex, Gemini CLI, and eight other coding agents into isolated git worktrees, then reviewing and merging their diffs from one UI.