pqc_nostd/lib.rs
1// ------------------------------------------------------------------------
2// PQC-COMBO v0.2.0
3// ------------------------------------------------------------------------
4// Copyright © 2025 Aaron Schnacky. All rights reserved.
5// License: MIT (publicly auditable for FIPS/CMVP verification)
6// Contact: aaronschnacky@gmail.com
7// src/lib.rs – FINAL GOLDEN VERSION
8//! # PQC-NOSTD
9//!
10//! Post-Quantum Cryptography library for `no_std` environments.
11//! Implements ML-KEM-1024 (FIPS 203) and ML-DSA-65 (FIPS 204).
12//!
13//! ## Features
14//! - `ml-kem`: Enables ML-KEM-1024.
15//! - `ml-dsa`: Enables ML-DSA-65.
16//! - `fips_140_3`: Enables FIPS 140-3 Approved mode (POST, CASTs, state machine).
17//!
18//! ## Approved-Mode Usage
19//!
20//! This example demonstrates the correct initialization and usage of the module in FIPS Approved mode.
21//!
22//! ```rust
23//! use pqc_nostd::{run_post_or_panic, is_operational, FIPS_CONTEXT};
24//! use pqc_nostd::auth::{login, Role};
25//!
26//! fn main() {
27//! // 1. Power-On Self-Tests (POST) MUST be run before any crypto operation.
28//! run_post_or_panic();
29//!
30//! // 2. Verify the module is in the Operational state.
31//! assert!(is_operational());
32//!
33//! // 3. Login as User (Level 2 Requirement)
34//! // In a real app, you would prompt for credentials.
35//! login(Role::User, b"user123").expect("Login failed");
36//!
37//! // 4. Use Approved Algorithms
38//!
39//! // ML-KEM-1024 (Key Encapsulation)
40//! let kyber_kp = pqc_nostd::kyber_generate_key_pair([0x01u8; 64]).unwrap();
41//! let (ct, ss_alice) = pqc_nostd::encapsulate(&kyber_kp.public_key(), [0x02u8; 32]).unwrap();
42//! let ss_bob = pqc_nostd::decapsulate(&kyber_kp.private_key(), &ct).unwrap();
43//! assert_eq!(ss_alice, ss_bob);
44//!
45//! // ML-DSA-65 (Digital Signatures)
46//! let dil_kp = pqc_nostd::dilithium_generate_key_pair([0x03u8; 32]).unwrap();
47//! let msg = b"FIPS 140-3 approved mode test";
48//! // Note: FIPS_CONTEXT is required for FIPS 204 compliance
49//! let sig = pqc_nostd::dilithium_sign(&dil_kp.signing_key, msg, FIPS_CONTEXT, [0x04u8; 32]).unwrap();
50//! assert!(pqc_nostd::dilithium_verify(&dil_kp.verification_key, msg, FIPS_CONTEXT, &sig).is_ok());
51//! }
52//! ```
53#![no_std]
54#![deny(missing_docs)]
55#![deny(unsafe_code)]
56
57/// Role-Based Authentication (Level 2).
58pub mod auth;
59/// Conditional Algorithm Self-Tests (CASTs).
60pub mod cast;
61/// Critical Security Parameter (CSP) management.
62/// Critical Security Parameter (CSP) management.
63pub mod csp;
64/// Error types and Result alias.
65pub mod error;
66/// Software Integrity Test (Level 1/2).
67pub mod integrity;
68/// Generated integrity data (HMAC).
69pub mod integrity_data;
70/// Known Answer Tests (KATs).
71#[cfg(feature = "fips_140_3")]
72pub mod kat;
73/// Pair-wise Consistency Tests (PCTs).
74pub mod pct;
75/// Pre-operational self-tests (POST).
76pub mod preop;
77/// FIPS module state management.
78pub mod state;
79
80/// ML-DSA-65 (FIPS 204) implementation.
81#[cfg(feature = "ml-dsa")]
82pub mod ml_dsa;
83/// ML-KEM-1024 (FIPS 203) implementation.
84#[cfg(feature = "ml-kem")]
85pub mod ml_kem;
86
87// ML-KEM re-exports
88#[cfg(feature = "ml-kem")]
89pub use ml_kem::{
90 decapsulate as kyber_decapsulate_internal, encapsulate as kyber_encapsulate_internal,
91 generate_key_pair as kyber_generate_key_pair_internal, KyberCiphertext, KyberKeypair,
92 KyberPrivateKey, KyberPublicKey, KyberSharedSecret,
93};
94
95#[cfg(any(feature = "ml-kem", feature = "ml-dsa"))]
96use auth::{check_authority, Role};
97
98/// Generates a Kyber key pair (Authenticated).
99#[cfg(feature = "ml-kem")]
100pub fn kyber_generate_key_pair(seed: [u8; 64]) -> Result<KyberKeypair> {
101 check_authority(Role::User)?;
102 Ok(kyber_generate_key_pair_internal(seed))
103}
104
105/// Encapsulates a shared secret (Authenticated).
106#[cfg(feature = "ml-kem")]
107pub fn encapsulate(
108 pk: &KyberPublicKey,
109 randomness: [u8; 32],
110) -> Result<(KyberCiphertext, KyberSharedSecret)> {
111 check_authority(Role::User)?;
112 Ok(kyber_encapsulate_internal(pk, randomness))
113}
114
115/// Decapsulates a shared secret (Authenticated).
116#[cfg(feature = "ml-kem")]
117pub fn decapsulate(sk: &KyberPrivateKey, ct: &KyberCiphertext) -> Result<KyberSharedSecret> {
118 check_authority(Role::User)?;
119 Ok(kyber_decapsulate_internal(sk, ct))
120}
121
122// ML-DSA re-exports
123#[cfg(feature = "ml-dsa")]
124pub use ml_dsa::{
125 generate_key_pair as dilithium_generate_key_pair_internal, sign as dilithium_sign_internal,
126 verify as dilithium_verify_internal, DilithiumKeypair, DilithiumSignature, DilithiumSigningKey,
127 DilithiumVerifyingKey, FIPS_CONTEXT,
128};
129
130/// Generates a Dilithium key pair (Authenticated).
131#[cfg(feature = "ml-dsa")]
132pub fn dilithium_generate_key_pair(seed: [u8; 32]) -> Result<DilithiumKeypair> {
133 check_authority(Role::User)?;
134 Ok(dilithium_generate_key_pair_internal(seed))
135}
136
137/// Signs a message (Authenticated).
138#[cfg(feature = "ml-dsa")]
139pub fn dilithium_sign(
140 sk: &DilithiumSigningKey,
141 msg: &[u8],
142 ctx: &[u8],
143 randomness: [u8; 32],
144) -> Result<DilithiumSignature> {
145 check_authority(Role::User)?;
146 dilithium_sign_internal(sk, msg, ctx, randomness).map_err(|_| PqcError::FipsErrorState)
147 // Map libcrux error if any
148}
149
150/// Verifies a signature (Authenticated).
151#[cfg(feature = "ml-dsa")]
152pub fn dilithium_verify(
153 pk: &DilithiumVerifyingKey,
154 msg: &[u8],
155 ctx: &[u8],
156 sig: &DilithiumSignature,
157) -> Result<()> {
158 check_authority(Role::User)?;
159 dilithium_verify_internal(pk, msg, ctx, sig).map_err(|_| PqcError::FipsErrorState)
160}
161
162/// ML-KEM-1024 public key size in bytes.
163pub const ML_KEM_1024_PK_BYTES: usize = 1568;
164/// ML-KEM-1024 secret key size in bytes.
165pub const ML_KEM_1024_SK_BYTES: usize = 3168;
166/// ML-KEM-1024 ciphertext size in bytes.
167pub const ML_KEM_1024_CT_BYTES: usize = 1568;
168/// ML-KEM-1024 shared secret size in bytes.
169pub const ML_KEM_1024_SS_BYTES: usize = 32;
170
171/// ML-DSA-65 public key size in bytes.
172pub const ML_DSA_65_PK_BYTES: usize = 1952;
173/// ML-DSA-65 secret key size in bytes.
174pub const ML_DSA_65_SK_BYTES: usize = 4032;
175/// ML-DSA-65 signature size in bytes.
176pub const ML_DSA_65_SIG_BYTES: usize = 3309;
177
178pub use error::{PqcError, Result};
179
180#[cfg(feature = "ml-kem")]
181pub use pct::kyber_pct;
182#[cfg(feature = "ml-dsa")]
183pub use pct::dilithium_pct;
184
185pub use preop::{run_post, run_post_or_panic};
186pub use state::{get_fips_state, is_operational, FipsState};
187
188// CSP aliases – only one definition each
189#[cfg(feature = "ml-kem")]
190pub use KyberPrivateKey as KyberSecretKey;
191
192// KyberSharedSecret is already re-exported above – do NOT re-export again
193// DilithiumSigningKey is already re-exported above – do NOT re-export again