quantica/lib.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Cédric Mesnil <cslashm@pm.me>
3
4//! # quantica — post-quantum cryptography for the `krypteia` workspace
5//!
6//! Pure-Rust implementations of the three NIST post-quantum standards,
7//! sharing the same side-channel countermeasure toolkit
8//! ([`silentops`](https://docs.rs/silentops)) used by the classical
9//! side of the workspace ([`arcana`](https://docs.rs/arcana)).
10//!
11//! | Module | Standard | Algorithm | Validation |
12//! |--------------|----------|----------------------------------------|------------------------------------------------|
13//! | [`ml_kem`] | FIPS 203 | ML-KEM (key encapsulation) | ACVP + Wycheproof |
14//! | [`ml_dsa`] | FIPS 204 | ML-DSA (digital signature) | ACVP + Wycheproof |
15//! | [`slh_dsa`] | FIPS 205 | SLH-DSA (hash-based digital signature) | ACVP (Wycheproof has no SLH-DSA corpus yet) |
16//!
17//! # Cargo features
18//!
19//! | Feature | Default | Effect |
20//! |---------|:-------:|--------|
21//! | `std` | **on** | Pulls in the standard library. Enables [`OsRng`](ml_kem::OsRng) and `std::error::Error` impls. |
22//! | `ml-kem` | **on** | Compiles the FIPS 203 module ([`ml_kem`]). |
23//! | `ml-dsa` | **on** | Compiles the FIPS 204 module ([`ml_dsa`]). |
24//! | `slh-dsa` | **on** | Compiles the FIPS 205 module ([`slh_dsa`]). |
25//! | `sca-protected` | **on** | Activates the masking + shuffled-NTT defences inside ML-KEM **and** ML-DSA (see below). |
26//! | `hazmat` | off | Exposes the expert building-block tier (see *API tiers* below). |
27//!
28//! Disable `std` for `no_std` builds: pass `--no-default-features`
29//! then re-enable the algorithms you need. The crate still requires
30//! `alloc` (keys, ciphertexts and signatures are `Vec<u8>`-backed).
31//!
32//! # API tiers
33//!
34//! The public surface is deliberately split in three tiers:
35//!
36//! 1. **Facade (guaranteed API)** — the typed entry points
37//! [`MlKem`](ml_kem::MlKem), [`MlDsa`](ml_dsa::MlDsa),
38//! [`SlhDsa`](slh_dsa::SlhDsa), their key/signature/ciphertext wrappers,
39//! the `params` and `rng` modules, [`prehash`] and [`secret`]. Semver
40//! applies here; this is what applications should use.
41//! 2. **`hazmat` (expert bricks, feature-gated, NO promise)** — the
42//! FIPS-level building blocks (byte encodings, samplers, Decompose/hints,
43//! the SLH-DSA address/tweakable-hash surface, the raw-slice algorithm
44//! facades and the deterministic `*_internal` CAVP entries). Offered for
45//! KAT/test-vector tooling and research. **No stability,
46//! misuse-resistance, or side-channel guarantee** — this tier may change
47//! in *any* release, and misusing some bricks (e.g. the unauthenticated
48//! component schemes) breaks the scheme's security.
49//! 3. **Internal** — everything else (`ntt`, `kpke`, WOTS+/XMSS/FORS, the
50//! masking/shuffling countermeasures, …) is `pub(crate)`: not reachable,
51//! not a compatibility surface.
52//!
53//! # Quick start
54//!
55//! ```no_run
56//! use quantica::ml_kem::*;
57//!
58//! let mut rng = OsRng;
59//! let (ek, dk) = MlKem::<MlKem768>::keygen(&mut rng).unwrap();
60//! let (ss_a, ct) = MlKem::<MlKem768>::encaps(&ek, &mut rng).unwrap();
61//! let ss_b = MlKem::<MlKem768>::decaps(&dk, &ct, &mut rng).unwrap();
62//! assert_eq!(ss_a, ss_b);
63//! // Both shared secrets auto-zeroize when they drop.
64//! ```
65//!
66//! # Typed key wrappers (Zeroize-on-Drop)
67//!
68//! The public API never returns raw `Vec<u8>` for secret material.
69//! Each algorithm exposes parameter-set-tagged wrapper types backed
70//! by the shared [`secret`] module:
71//!
72//! | Module | Public (not zeroized) | Secret (Drop-zeroizes) |
73//! |------------|---------------------------------------------|----------------------------------------------|
74//! | [`ml_kem`] | [`EncapsulationKey<P>`](ml_kem::EncapsulationKey), [`Ciphertext<P>`](ml_kem::Ciphertext) | [`DecapsulationKey<P>`](ml_kem::DecapsulationKey), [`SharedSecret`](ml_kem::SharedSecret) |
75//! | [`ml_dsa`] | [`VerifyingKey<P>`](ml_dsa::VerifyingKey), [`Signature<P>`](ml_dsa::Signature) | [`SigningKey<P>`](ml_dsa::SigningKey) |
76//! | [`slh_dsa`]| [`VerifyingKey<P>`](slh_dsa::VerifyingKey), [`Signature<P>`](slh_dsa::Signature) | [`SigningKey<P>`](slh_dsa::SigningKey) |
77//!
78//! All wrappers implement `from_bytes(&[u8])` (length-validated),
79//! `as_bytes()`, `Deref<Target=[u8]>`, `AsRef<[u8]>` and `Clone`.
80//! Secret variants have a **redacted `Debug`** impl
81//! (`<redacted; len=N>`) so stray logging cannot leak key material.
82//!
83//! The raw byte-slice paths (`ml_kem::kem::*`, `ml_dsa::dsa::*`,
84//! `slh_dsa::slh::*`) are exposed **only** under the `hazmat` Cargo
85//! feature — `pub(crate)` otherwise — for ACVP/CAVP tooling and the
86//! C FFI. See the `hazmat` tier in *API tiers* above.
87//!
88//! # Side-channel countermeasures
89//!
90//! ## Always-on (every build)
91//!
92//! | Defence | Algorithms | Threat addressed |
93//! |-----------------------|---------------------|---------------------------------|
94//! | Constant-time arith | all three | Timing / cache / basic SPA |
95//! | Zeroize-on-Drop | all three | Cold boot, memory dumps, UAF |
96//! | Volatile zeroization | all three | Same, on intermediates |
97//! | Double Decaps | ML-KEM | DFA on FO comparison |
98//! | dk integrity check | ML-KEM | DFA on stored key material |
99//! | Hedged signing | ML-DSA, SLH-DSA | Fault-induced nonce reuse |
100//!
101//! ## `sca-protected` (on by default)
102//!
103//! | Defence | Algorithms | Module |
104//! |-------------------------------|-----------------|---------------------------------------|
105//! | First-order additive masking | ML-KEM, ML-DSA | `ml_kem::masked`, `ml_dsa::masked` (internal) |
106//! | Shuffled NTT (Fisher-Yates) | ML-KEM, ML-DSA | `ml_kem::shuffle`, `ml_dsa::shuffle` (internal) |
107//! | Mask refresh between rounds | ML-DSA | `MaskedPoly::refresh()` per rejection iteration |
108//!
109//! The masking layer is mathematically transparent: `unmask(op(mask(s), public)) ≡ op(s, public)`.
110//! All NIST ACVP vectors pass unchanged with `sca-protected` enabled — the masked path produces
111//! **bit-identical** signatures and shared secrets.
112//!
113//! SLH-DSA is purely hash-based and has no algebraic structure to
114//! mask; the always-on defences are the relevant layer there.
115//!
116//! # `no_std`
117//!
118//! `quantica` is `std`-by-default, but the standard library is gated
119//! behind the `std` feature. Building with
120//! `--no-default-features --features ml-kem,ml-dsa,slh-dsa,sca-protected`
121//! produces a `no_std` crate that still depends on `alloc` (because
122//! the algorithms allocate heap buffers for keys, ciphertexts and
123//! signatures). In `no_std` mode:
124//!
125//! * The OS-backed `OsRng` is not available — callers must provide
126//! their own [`CryptoRng`](ml_kem::CryptoRng) implementation
127//! (typically wrapping a hardware RNG on embedded targets).
128//! * The error enums no longer implement [`std::error::Error`].
129//!
130//! Cross-compile validated on `thumbv7em-none-eabihf` (Cortex-M4),
131//! `thumbv6m-none-eabi` (Cortex-M0), and `riscv32imc-unknown-none-elf`
132//! (ESP32-C3) with all three algorithms + `sca-protected` enabled.
133//!
134//! # Examples
135//!
136//! ```bash
137//! cargo run --release -p quantica --example ml_kem_roundtrip
138//! cargo run --release -p quantica --example ml_dsa_sign_verify
139//! cargo run --release -p quantica --example slh_dsa_sign_verify
140//! ```
141
142#![cfg_attr(not(feature = "std"), no_std)]
143
144#[macro_use]
145extern crate alloc;
146
147// Bring `Vec` into scope for all submodules without forcing a per-file
148// `use alloc::vec::Vec;`. The `vec!` macro is brought in via the
149// `#[macro_use] extern crate alloc;` above.
150#[allow(unused_imports)]
151pub(crate) use alloc::vec::Vec;
152
153// Shared Keccak-f[1600] core used by every algorithm. Crate-private:
154// each algorithm exposes its own thin `sha3` wrapper module on top.
155#[cfg(any(feature = "ml-kem", feature = "ml-dsa", feature = "slh-dsa"))]
156mod sha3;
157
158/// Pre-hash selector ([`prehash::PreHash`]) and `M′` message encoding
159/// shared by the ML-DSA and SLH-DSA external signature APIs
160/// (FIPS 204 §5.4 / FIPS 205 §10.2).
161#[cfg(any(feature = "ml-dsa", feature = "slh-dsa"))]
162pub mod prehash;
163
164/// Zeroize-on-Drop wrappers for secret key material
165/// ([`SecretBytes`](secret::SecretBytes), [`SecretArray`](secret::SecretArray)).
166#[cfg(any(feature = "ml-kem", feature = "ml-dsa", feature = "slh-dsa"))]
167pub mod secret;
168
169// Shared dependency-free JSON/`.rsp` helpers for the in-crate `acvp_internal`
170// KAT modules (which drive the `pub(crate)` `*_internal` functions).
171#[cfg(all(test, any(feature = "ml-dsa", feature = "slh-dsa")))]
172mod kat_json;
173
174#[cfg(feature = "ml-kem")]
175pub mod ml_kem;
176
177#[cfg(feature = "ml-dsa")]
178pub mod ml_dsa;
179
180#[cfg(feature = "slh-dsa")]
181pub mod slh_dsa;