⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/crypto/post_quantum/
mod.rs

1//! Post-Quantum Cryptography
2//!
3//! Implements ML-DSA (Dilithium) signatures and ML-KEM (Kyber) key
4//! encapsulation.
5//!
6//! ## NIST Standards Compliance
7//!
8//! This module implements algorithms selected by NIST for post-quantum
9//! cryptography:
10//! - **ML-DSA (FIPS 204)**: Module-Lattice-Based Digital Signature Algorithm
11
12// Post-quantum cryptography -- covers sub-module constants per NIST specs
13#![allow(dead_code)]
14//!   - Replaces Dilithium after standardization
15//!   - Provides quantum-resistant digital signatures
16//!   - Security levels: 2, 3, 5 (128, 192, 256-bit equivalents)
17//! - **ML-KEM (FIPS 203)**: Module-Lattice-Based Key Encapsulation Mechanism
18//!   - Replaces Kyber after standardization
19//!   - Provides quantum-resistant key exchange
20//!   - Security levels: 512, 768, 1024 (128, 192, 256-bit equivalents)
21//!
22//! ## Implementation Status
23//!
24//! **Current**: Lattice-based implementations with NTT polynomial arithmetic
25//! **Production Requirements**:
26//! - Full NIST-compliant algorithm implementations
27//! - Constant-time operations to prevent timing attacks
28//! - Proper random number generation from hardware
29//! - Side-channel attack mitigations
30//! - FIPS 140-3 validation for cryptographic modules
31//!
32//! ## Integration with Classical Cryptography
33//!
34//! Hybrid key exchange combines classical (X25519) and post-quantum (Kyber) to
35//! provide:
36//! - Security against both classical and quantum attacks
37//! - Backward compatibility during transition period
38//! - Meet-in-the-middle security guarantees
39
40mod dilithium;
41mod hybrid;
42pub mod kyber;
43
44use alloc::vec::Vec;
45
46// ============================================================================
47// Shared Types
48// ============================================================================
49
50/// Dilithium security levels
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub(crate) enum DilithiumLevel {
53    Level2, // ~128 bits security
54    Level3, // ~192 bits security
55    Level5, // ~256 bits security
56}
57
58/// Kyber security levels
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub(crate) enum KyberLevel {
61    Kyber512,  // ~128 bits security
62    Kyber768,  // ~192 bits security
63    Kyber1024, // ~256 bits security
64}
65
66// ============================================================================
67// Shared Constants and Utility Functions
68// ============================================================================
69
70/// Kyber modulus
71const KYBER_Q: u32 = 3329;
72/// Polynomial degree
73const KYBER_N: usize = 256;
74
75/// Primitive 256th root of unity mod q=3329
76/// zeta = 17 (since 17^128 = -1 mod 3329)
77const KYBER_ZETA: u32 = 17;
78
79/// Bit-reverse a 7-bit number
80fn bit_reverse_7(x: u8) -> u8 {
81    let mut r = 0u8;
82    let mut v = x;
83    let mut i = 0;
84    while i < 7 {
85        r = (r << 1) | (v & 1);
86        v >>= 1;
87        i += 1;
88    }
89    r
90}
91
92/// Modular exponentiation: base^exp mod modulus
93fn mod_pow(base: u32, exp: u32, modulus: u32) -> u32 {
94    if modulus == 1 {
95        return 0;
96    }
97    let mut result: u64 = 1;
98    let mut base = (base % modulus) as u64;
99    let modulus = modulus as u64;
100    let mut exp = exp;
101    while exp > 0 {
102        if exp & 1 == 1 {
103            result = (result * base) % modulus;
104        }
105        exp >>= 1;
106        base = (base * base) % modulus;
107    }
108    result as u32
109}
110
111/// Barrett reduction for Kyber: reduce a to [0, q)
112fn kyber_barrett_reduce(a: i32) -> i32 {
113    /// Barrett reduction constant for Kyber
114    const KYBER_BARRETT_V: u32 = 20159; // round(2^26 / q)
115
116    let q = KYBER_Q as i32;
117    // t = (a * v) >> 26 where v = round(2^26 / q)
118    let t = ((a as i64 * KYBER_BARRETT_V as i64) >> 26) as i32;
119    let r = a - t * q;
120    // Result may still be >= q, one conditional subtraction
121    if r >= q {
122        r - q
123    } else if r < 0 {
124        r + q
125    } else {
126        r
127    }
128}
129
130/// Expand a seed into pseudorandom bytes using SHA-256 in counter mode
131fn expand_seed(seed: &[u8], len: usize) -> Vec<u8> {
132    use super::hash::sha256;
133    let mut result = Vec::with_capacity(len);
134    let mut counter: u32 = 0;
135
136    while result.len() < len {
137        let mut input = Vec::with_capacity(seed.len() + 4);
138        input.extend_from_slice(seed);
139        input.extend_from_slice(&counter.to_le_bytes());
140        let hash = sha256(&input);
141        let remaining = len - result.len();
142        let take = core::cmp::min(remaining, 32);
143        result.extend_from_slice(&hash.as_bytes()[..take]);
144        counter += 1;
145    }
146    result
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152
153    // These tests require bare-metal PRNG initialization for deterministic results.
154    // The simplified post-quantum implementations produce non-deterministic output
155    // without the full kernel entropy sources available on the host target.
156    #[cfg(target_os = "none")]
157    #[test]
158    fn test_dilithium_signing() {
159        let signing_key = DilithiumSigningKey::generate(DilithiumLevel::Level2).unwrap();
160        let verifying_key = signing_key.verifying_key();
161
162        let message = b"Hello, Post-Quantum World!";
163        let signature = signing_key.sign(message).unwrap();
164
165        assert!(verifying_key.verify(message, &signature).unwrap());
166    }
167
168    #[cfg(target_os = "none")]
169    #[test]
170    fn test_kyber_kem() {
171        let secret_key = KyberSecretKey::generate(KyberLevel::Kyber768).unwrap();
172        let public_key = secret_key.public_key();
173
174        let (ciphertext, shared_secret1) = public_key.encapsulate().unwrap();
175        let shared_secret2 = secret_key.decapsulate(&ciphertext).unwrap();
176
177        // Secrets should match
178        assert_eq!(shared_secret1.as_bytes(), shared_secret2.as_bytes());
179    }
180
181    #[test]
182    fn test_hybrid_exchange() {
183        let alice = HybridKeyExchange::generate(KyberLevel::Kyber768).unwrap();
184        let bob = HybridKeyExchange::generate(KyberLevel::Kyber768).unwrap();
185
186        let (alice_classical_pub, alice_pq_pub) = alice.public_keys();
187        let (bob_classical_pub, bob_pq_pub) = bob.public_keys();
188
189        let (bob_pq_ct, _) = alice_pq_pub.encapsulate().unwrap();
190
191        let alice_shared = alice.exchange(&bob_classical_pub, &bob_pq_ct).unwrap();
192
193        // Just verify it completes without error
194        assert_eq!(alice_shared.len(), 32);
195    }
196}