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}