krypteia-quantica 0.1.0

Pure-Rust post-quantum cryptography: FIPS 203 ML-KEM, FIPS 204 ML-DSA, and FIPS 205 SLH-DSA. First-order arithmetic masking, shuffled NTT, FORS recompute-and-compare redundancy, constant-time rejection sampling. Targets embedded (no_std), STM32 M0/M4/M33, ESP32-C3 RISC-V. Zero runtime dependencies.
Documentation
//! # quantica — post-quantum cryptography for the `krypteia` workspace
//!
//! Pure-Rust implementations of the three NIST post-quantum standards,
//! sharing the same side-channel countermeasure toolkit
//! ([`silentops`](https://docs.rs/silentops)) used by the classical
//! side of the workspace ([`arcana`](https://docs.rs/arcana)).
//!
//! | Module       | Standard | Algorithm                              | Validation                                     |
//! |--------------|----------|----------------------------------------|------------------------------------------------|
//! | [`ml_kem`]   | FIPS 203 | ML-KEM (key encapsulation)             | ACVP + Wycheproof                              |
//! | [`ml_dsa`]   | FIPS 204 | ML-DSA (digital signature)             | ACVP + Wycheproof                              |
//! | [`slh_dsa`]  | FIPS 205 | SLH-DSA (hash-based digital signature) | ACVP (Wycheproof has no SLH-DSA corpus yet)    |
//!
//! # Cargo features
//!
//! | Feature | Default | Effect |
//! |---------|:-------:|--------|
//! | `std`   | **on**  | Pulls in the standard library. Enables [`OsRng`](ml_kem::OsRng) and `std::error::Error` impls. |
//! | `ml-kem` | **on** | Compiles the FIPS 203 module ([`ml_kem`]). |
//! | `ml-dsa` | **on** | Compiles the FIPS 204 module ([`ml_dsa`]). |
//! | `slh-dsa` | **on** | Compiles the FIPS 205 module ([`slh_dsa`]). |
//! | `sca-protected` | **on** | Activates the masking + shuffled-NTT defences inside ML-KEM **and** ML-DSA (see below). |
//!
//! Disable `std` for `no_std` builds: pass `--no-default-features`
//! then re-enable the algorithms you need. The crate still requires
//! `alloc` (keys, ciphertexts and signatures are `Vec<u8>`-backed).
//!
//! # Quick start
//!
//! ```no_run
//! use quantica::ml_kem::*;
//!
//! let mut rng = OsRng;
//! let (ek, dk) = MlKem::<MlKem768>::keygen(&mut rng).unwrap();
//! let (ss_a, ct) = MlKem::<MlKem768>::encaps(&ek, &mut rng).unwrap();
//! let ss_b = MlKem::<MlKem768>::decaps(&dk, &ct, &mut rng).unwrap();
//! assert_eq!(ss_a, ss_b);
//! // Both shared secrets auto-zeroize when they drop.
//! ```
//!
//! # Typed key wrappers (Zeroize-on-Drop)
//!
//! The public API never returns raw `Vec<u8>` for secret material.
//! Each algorithm exposes parameter-set-tagged wrapper types backed
//! by the shared [`secret`] module:
//!
//! | Module     | Public (not zeroized)                       | Secret (Drop-zeroizes)                      |
//! |------------|---------------------------------------------|----------------------------------------------|
//! | [`ml_kem`] | [`EncapsulationKey<P>`](ml_kem::EncapsulationKey), [`Ciphertext<P>`](ml_kem::Ciphertext) | [`DecapsulationKey<P>`](ml_kem::DecapsulationKey), [`SharedSecret`](ml_kem::SharedSecret) |
//! | [`ml_dsa`] | [`VerifyingKey<P>`](ml_dsa::VerifyingKey), [`Signature<P>`](ml_dsa::Signature) | [`SigningKey<P>`](ml_dsa::SigningKey) |
//! | [`slh_dsa`]| [`VerifyingKey<P>`](slh_dsa::VerifyingKey), [`Signature<P>`](slh_dsa::Signature) | [`SigningKey<P>`](slh_dsa::SigningKey) |
//!
//! All wrappers implement `from_bytes(&[u8])` (length-validated),
//! `as_bytes()`, `Deref<Target=[u8]>`, `AsRef<[u8]>` and `Clone`.
//! Secret variants have a **redacted `Debug`** impl
//! (`<redacted; len=N>`) so stray logging cannot leak key material.
//!
//! The internal byte-slice API (`ml_kem::kem::*`, `ml_dsa::dsa::*`,
//! `slh_dsa::slh::*`) is still public for ACVP/CAVP testing and
//! for the C FFI.
//!
//! # Side-channel countermeasures
//!
//! ## Always-on (every build)
//!
//! | Defence               | Algorithms          | Threat addressed               |
//! |-----------------------|---------------------|---------------------------------|
//! | Constant-time arith   | all three           | Timing / cache / basic SPA     |
//! | Zeroize-on-Drop       | all three           | Cold boot, memory dumps, UAF   |
//! | Volatile zeroization  | all three           | Same, on intermediates         |
//! | Double Decaps         | ML-KEM              | DFA on FO comparison           |
//! | dk integrity check    | ML-KEM              | DFA on stored key material     |
//! | Hedged signing        | ML-DSA, SLH-DSA     | Fault-induced nonce reuse      |
//!
//! ## `sca-protected` (on by default)
//!
//! | Defence                       | Algorithms      | Module                                |
//! |-------------------------------|-----------------|---------------------------------------|
//! | First-order additive masking  | ML-KEM, ML-DSA  | [`ml_kem::masked`], [`ml_dsa::masked`] |
//! | Shuffled NTT (Fisher-Yates)   | ML-KEM, ML-DSA  | [`ml_kem::shuffle`], [`ml_dsa::shuffle`] |
//! | Mask refresh between rounds   | ML-DSA          | `MaskedPoly::refresh()` per rejection iteration |
//!
//! The masking layer is mathematically transparent: `unmask(op(mask(s), public)) ≡ op(s, public)`.
//! All NIST ACVP vectors pass unchanged with `sca-protected` enabled — the masked path produces
//! **bit-identical** signatures and shared secrets.
//!
//! SLH-DSA is purely hash-based and has no algebraic structure to
//! mask; the always-on defences are the relevant layer there.
//!
//! # `no_std`
//!
//! `quantica` is `std`-by-default, but the standard library is gated
//! behind the `std` feature. Building with
//! `--no-default-features --features ml-kem,ml-dsa,slh-dsa,sca-protected`
//! produces a `no_std` crate that still depends on `alloc` (because
//! the algorithms allocate heap buffers for keys, ciphertexts and
//! signatures). In `no_std` mode:
//!
//! * The OS-backed `OsRng` is not available — callers must provide
//!   their own [`CryptoRng`](ml_kem::CryptoRng) implementation
//!   (typically wrapping a hardware RNG on embedded targets).
//! * The error enums no longer implement [`std::error::Error`].
//!
//! Cross-compile validated on `thumbv7em-none-eabihf` (Cortex-M4),
//! `thumbv6m-none-eabi` (Cortex-M0), and `riscv32imc-unknown-none-elf`
//! (ESP32-C3) with all three algorithms + `sca-protected` enabled.
//!
//! # Examples
//!
//! ```bash
//! cargo run --release -p quantica --example ml_kem_roundtrip
//! cargo run --release -p quantica --example ml_dsa_sign_verify
//! cargo run --release -p quantica --example slh_dsa_sign_verify
//! ```

#![cfg_attr(not(feature = "std"), no_std)]

#[macro_use]
extern crate alloc;

// Bring `Vec` into scope for all submodules without forcing a per-file
// `use alloc::vec::Vec;`. The `vec!` macro is brought in via the
// `#[macro_use] extern crate alloc;` above.
#[allow(unused_imports)]
pub(crate) use alloc::vec::Vec;

// Shared Keccak-f[1600] core used by every algorithm. Crate-private:
// each algorithm exposes its own thin `sha3` wrapper module on top.
#[cfg(any(feature = "ml-kem", feature = "ml-dsa", feature = "slh-dsa"))]
mod sha3;

/// Zeroize-on-Drop wrappers for secret key material
/// ([`SecretBytes`](secret::SecretBytes), [`SecretArray`](secret::SecretArray)).
#[cfg(any(feature = "ml-kem", feature = "ml-dsa", feature = "slh-dsa"))]
pub mod secret;

#[cfg(feature = "ml-kem")]
pub mod ml_kem;

#[cfg(feature = "ml-dsa")]
pub mod ml_dsa;

#[cfg(feature = "slh-dsa")]
pub mod slh_dsa;