1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//! # ferritls-core
//!
//! Pure-Rust cryptographic primitives, providing everything that
//! [ferritls-rustls](https://docs.rs/ferritls-rustls) (the rustls
//! `CryptoProvider` adapter) needs. No C, no assembly, no `unsafe`.
//!
//! ## FIPS 140-3 module boundary
//!
//! This crate is the **module boundary** intended for future CMVP
//! validation: every algorithm is implemented in-boundary in pure Rust
//! (`#![forbid(unsafe_code)]`), and the dependency whitelist is exactly
//! [`subtle`], [`zeroize`] and [`getrandom`] (OS entropy input). New
//! dependencies require updating the whitelist and audit rationale in
//! `docs/FIPS.md` first (AGENTS.md hard rule 2).
//!
//! Note that the module is **not yet CMVP-validated**; the `fips` cargo
//! feature selects the approved-algorithm mode, it is not a
//! certification claim.
//!
//! ## Default feature `simd`
//!
//! The default `simd` feature uses the standard library's `core::simd`
//! (portable_simd) for explicit vectorization of the AES and ChaCha20
//! hot paths — `std` code, not a third-party dependency, so the
//! whitelist is unchanged. On the **stable toolchain** it compiles via
//! `RUSTC_BOOTSTRAP=1` (provided by this repository's
//! `.cargo/config.toml`; downstream users set the env themselves or opt
//! out with `default-features = false`, which keeps the scalar fallback
//! path). Vector width follows the compile target (SSE2/NEON baseline,
//! widening to AVX2/AVX-512 with the corresponding `target-feature`
//! RUSTFLAGS); there is no runtime dispatch and no `unsafe`.
//!
//! ## Usage
//!
//! Hashing:
//!
//! ```
//! use ferritls_core::sha2::Sha256;
//!
//! let digest = Sha256::one_shot(b"abc");
//! assert_eq!(&digest[..4], &[0xba, 0x78, 0x16, 0xbf]); // FIPS 180-4 example
//! ```
//!
//! Authenticated encryption (AES-128-GCM; the same shape exists for
//! [`gcm::Aes256Gcm`], [`ccm`] and [`chacha20poly1305`]):
//!
//! ```
//! use ferritls_core::gcm::Aes128Gcm;
//!
//! let cipher = Aes128Gcm::new(&[7u8; 16]);
//! let nonce = [9u8; 12]; // unique per key — never repeat a (key, nonce) pair
//!
//! let ct_and_tag = cipher.seal(&nonce, b"aad", b"plaintext");
//! let plaintext = cipher.open(&nonce, b"aad", &ct_and_tag).expect("authentic");
//! assert_eq!(plaintext, b"plaintext");
//!
//! // Tampered ciphertexts fail verification before any plaintext is returned:
//! let mut tampered = ct_and_tag.clone();
//! tampered[0] ^= 0x01;
//! assert!(cipher.open(&nonce, b"aad", &tampered).is_err());
//! ```
//!
//! Key agreement, signatures, KEMs and the DRBG follow the same pattern:
//! typed keys, explicit errors (no panics on attacker-controlled input),
//! and zeroization of secret material on drop.
//!
//! ## Module map
//!
//! | Module | Contents | FIPS approval |
//! |---|---|---|
//! | [`sha2`] | SHA-256/384/512 | approved |
//! | [`sha3`] | SHA3-224/256/384/512, SHAKE-128/256 (full FIPS 202 family) | approved |
//! | [`hmac`] / [`hkdf`] | HMAC, HKDF | approved |
//! | [`aes`] / [`gcm`] / [`ccm`] | AES, AES-GCM, AES-CCM | approved |
//! | [`chacha20poly1305`] | ChaCha20-Poly1305 | not approved |
//! | [`ecdh`] | X25519 (not approved), P-256/384 (approved) | mixed |
//! | [`mlkem`] | ML-KEM-512/768/1024 (FIPS 203) | approved |
//! | [`sign`] | ECDSA, RSA (approved), Ed25519 (not approved) | mixed |
//! | [`drbg`] / [`entropy`] | SP 800-90A CTR-DRBG, OS entropy | approved |
//! | [`selftest`] | Power-on self-tests (KATs) | required |
//! | [`der`] | Minimal DER/PKCS#8/SEC1 parsing | — |
//! | [`ct`] / [`policy`] / [`ops`] | Constant-time utilities, approval policy, backend dispatch | — |
//!
//! All modules are fully implemented and covered by official
//! NIST/RFC/CAVP vectors, Wycheproof and the RFC 8448 key schedule (see
//! `docs/VECTOR-PROVENANCE.md` for sources). AES-GCM and SHA-256 public
//! types dispatch through [`ops`]: the default is a zero-overhead direct
//! software path, and an optional out-of-boundary hardware backend crate
//! can be installed to replace the execution core (see [`ops`]).
// Default feature `simd`: explicit core::simd (portable_simd) paths — std
// code, entirely safe. On stable toolchains the feature gate compiles via
// RUSTC_BOOTSTRAP=1 (repo .cargo/config.toml [env] / CI env; downstream
// users provide the env or opt out with default-features = false, which
// keeps the scalar fallback). Constraints and lane-width selection rules:
// AGENTS.md §5.5. Remove the bootstrap dependency once portable_simd
// stabilizes.
// Future hardware backends (AES-NI/SHA extensions) inevitably need unsafe;
// they must not enter this crate — they live in separate out-of-boundary
// backend crates hooked up through the ops module traits (see the ops
// module docs and docs/ARCHITECTURE.md). Whether such a backend ever joins
// the FIPS boundary is a phase-C decision.
/// Compile canary for the `simd` feature: ensures portable_simd is truly
/// available in the current configuration (the hot paths live in the
/// [`aes`] and [`chacha20poly1305`] modules).
pub use Approval;
/// The unified error type of the module boundary.
///
/// Rule: attacker-controlled input (network data, certificates, key
/// files) must never panic — every failure is returned as this error
/// (AGENTS.md hard rule 4). `non_exhaustive`: variants may be added as
/// milestones land.