citadel_pqcrypto/
constructor_opts.rs

1//! Post-Quantum Cryptography Construction Options
2//!
3//! This module provides configuration and initialization options for post-quantum
4//! cryptographic (PQC) operations in the Citadel Protocol. It includes structures for:
5//!
6//! - Configuring PQC instance parameters
7//! - Managing recursive key derivation chains
8//! - Handling shared secrets between participants
9//!
10//! # Features
11//!
12//! - Flexible cryptographic parameter configuration
13//! - Secure recursive key derivation chain management
14//! - Support for multi-round key exchanges
15//! - Memory-safe secret handling
16//!
17//! # Examples
18//!
19//! ```rust
20//! use citadel_pqcrypto::constructor_opts::{ConstructorOpts, RecursiveChain};
21//! use citadel_types::crypto::CryptoParameters;
22//!
23//! // Create initial constructor options
24//! let opts = ConstructorOpts::new_init(Some(CryptoParameters::default()));
25//!
26//! // Create chain for key derivation
27//! let chain = [1u8; 32];
28//! let alice = [2u8; 32];
29//! let bob = [3u8; 32];
30//! let chain = RecursiveChain::new(chain, alice, bob, true).unwrap();
31//! ```
32//!
33//! # Security Considerations
34//!
35//! - All cryptographic parameters should be chosen based on security requirements
36//! - Chain values must be protected and never exposed outside secure contexts
37//! - Previous shared secrets should be carefully managed and zeroized after use
38//! - Memory safety is critical for protecting sensitive key material
39//!
40//! # Related Components
41//!
42//! - [`citadel_types::crypto`] - Core cryptographic types and parameters
43//! - [`citadel_pqcrypto::wire`] - Wire protocol for PQC operations
44//! - [`citadel_pqcrypto::key_store`] - Secure key storage functionality
45
46use citadel_types::crypto::CryptoParameters;
47use citadel_types::prelude::SecurityLevel;
48use serde::{Deserialize, Serialize};
49
50/// WARNING! this struct, especially the `chain`, should never leave a node; it should only be extracted from the previous PQC when bob is constructing his PQC
51#[derive(Clone, Default)]
52pub struct ConstructorOpts {
53    pub cryptography: Option<CryptoParameters>,
54    pub chain: Option<RecursiveChain>,
55}
56
57pub trait ImpliedSecurityLevel {
58    fn implied_security_level(&self) -> SecurityLevel;
59}
60
61impl ImpliedSecurityLevel for Vec<ConstructorOpts> {
62    fn implied_security_level(&self) -> SecurityLevel {
63        assert!(
64            !self.is_empty(),
65            "Security level cannot be derived from an empty vector"
66        );
67        assert!(
68            self.len() < u8::MAX as usize,
69            "Security level does not fit in u8"
70        );
71        SecurityLevel::from(self.len().saturating_sub(1) as u8)
72    }
73}
74
75impl ConstructorOpts {
76    /// Starts off a f(0) chain with a single layer of ratcheting
77    pub fn new_init(cryptography: Option<impl Into<CryptoParameters>>) -> Self {
78        Self {
79            cryptography: cryptography.map(|r| r.into()),
80            chain: None,
81        }
82    }
83
84    pub fn new_vec_init(
85        cryptography: Option<impl Into<CryptoParameters>>,
86        security_level: SecurityLevel,
87    ) -> Vec<Self> {
88        let count = security_level.value() as usize + 1;
89        let settings = cryptography.map(|r| r.into()).unwrap_or_default();
90        (0..count).map(|_| Self::new_init(Some(settings))).collect()
91    }
92
93    /// Generates a new f(n) -> f(n +1) chain
94    pub fn new_ratcheted(
95        cryptography: Option<impl Into<CryptoParameters>>,
96        previous_shared_secret: RecursiveChain,
97    ) -> Self {
98        Self {
99            cryptography: cryptography.map(|r| r.into()),
100            chain: Some(previous_shared_secret),
101        }
102    }
103}
104
105#[derive(Clone, Serialize, Deserialize)]
106pub struct RecursiveChain {
107    pub chain: [u8; 32],
108    pub alice: [u8; 32],
109    pub bob: [u8; 32],
110    pub(crate) first: bool,
111}
112
113impl RecursiveChain {
114    pub fn new<T: AsRef<[u8]>, R: AsRef<[u8]>, V: AsRef<[u8]>>(
115        chain: T,
116        alice: R,
117        bob: V,
118        first: bool,
119    ) -> Option<Self> {
120        let chain = chain.as_ref();
121        let alice = alice.as_ref();
122        let bob = bob.as_ref();
123
124        if chain.len() != 32 || alice.len() != 32 || bob.len() != 32 {
125            None
126        } else {
127            let mut chain_ret: [u8; 32] = [0u8; 32];
128            let mut alice_ret: [u8; 32] = [0u8; 32];
129            let mut bob_ret: [u8; 32] = [0u8; 32];
130
131            for (idx, val) in chain.iter().enumerate() {
132                chain_ret[idx] = *val;
133            }
134
135            for (idx, val) in alice.iter().enumerate() {
136                alice_ret[idx] = *val;
137            }
138
139            for (idx, val) in bob.iter().enumerate() {
140                bob_ret[idx] = *val;
141            }
142
143            Some(Self {
144                chain: chain_ret,
145                alice: alice_ret,
146                bob: bob_ret,
147                first,
148            })
149        }
150    }
151}