phantom_protocol/transport/
device_profile.rs1use crate::crypto::adaptive_crypto::{CipherSuite, HwCaps};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum DeviceTier {
15 Constrained,
18 Standard,
21 Performance,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum PqKemLevel {
29 Kyber512,
31 Kyber768,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum PqSignLevel {
38 Dilithium2,
40 Dilithium3,
42}
43
44#[derive(Debug, Clone)]
46pub struct DeviceProfile {
47 pub tier: DeviceTier,
49 pub cipher: CipherSuite,
51 pub pq_kem: PqKemLevel,
53 pub pq_sign: PqSignLevel,
55 pub buffer_size: usize,
57 pub max_streams: u16,
59 pub coalescing: bool,
61 pub max_datagram_size: usize,
63 pub compression: bool,
65 pub max_payload: usize,
67}
68
69impl DeviceProfile {
70 pub fn auto_detect() -> Self {
72 let caps = HwCaps::detect();
73 let available_ram = Self::estimate_available_ram();
74
75 let tier = if available_ram < 1_048_576 {
76 DeviceTier::Constrained
78 } else if available_ram < 512_000_000 {
79 DeviceTier::Standard
81 } else {
82 DeviceTier::Performance
83 };
84
85 Self::for_tier(tier, &caps)
86 }
87
88 pub fn for_tier(tier: DeviceTier, caps: &HwCaps) -> Self {
90 match tier {
91 DeviceTier::Constrained => Self {
92 tier,
93 cipher: CipherSuite::ChaCha20Poly1305, pq_kem: PqKemLevel::Kyber512, pq_sign: PqSignLevel::Dilithium2, buffer_size: 2 * 1024, max_streams: 4,
98 coalescing: false, max_datagram_size: 512, compression: false, max_payload: 256,
102 },
103 DeviceTier::Standard => Self {
104 tier,
105 cipher: caps.recommended_cipher(), pq_kem: PqKemLevel::Kyber768, pq_sign: PqSignLevel::Dilithium3, buffer_size: 16 * 1024, max_streams: 64,
110 coalescing: true,
111 max_datagram_size: 4096,
112 compression: true, max_payload: 1400, },
115 DeviceTier::Performance => Self {
116 tier,
117 cipher: CipherSuite::Aes256Gcm, pq_kem: PqKemLevel::Kyber768, pq_sign: PqSignLevel::Dilithium3, buffer_size: 64 * 1024, max_streams: 256,
122 coalescing: true,
123 max_datagram_size: 8192, compression: true, max_payload: 8192,
126 },
127 }
128 }
129
130 pub fn constrained() -> Self {
132 Self::for_tier(DeviceTier::Constrained, &HwCaps { has_hw_aes: false })
133 }
134
135 pub fn standard() -> Self {
136 Self::for_tier(DeviceTier::Standard, &HwCaps::detect())
137 }
138
139 pub fn performance() -> Self {
140 Self::for_tier(DeviceTier::Performance, &HwCaps { has_hw_aes: true })
141 }
142
143 fn estimate_available_ram() -> usize {
145 #[cfg(target_pointer_width = "64")]
148 {
149 8_000_000_000
150 } #[cfg(target_pointer_width = "32")]
153 {
154 512_000
155 } #[cfg(not(any(target_pointer_width = "64", target_pointer_width = "32")))]
158 {
159 256_000
160 } }
162
163 pub fn is_full_pq(&self) -> bool {
165 matches!(self.pq_kem, PqKemLevel::Kyber768)
166 }
167
168 pub fn tier_byte(&self) -> u8 {
170 match self.tier {
171 DeviceTier::Constrained => 0,
172 DeviceTier::Standard => 1,
173 DeviceTier::Performance => 2,
174 }
175 }
176}
177
178impl std::fmt::Display for DeviceProfile {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 write!(
181 f,
182 "{:?} [cipher={:?}, kem={:?}, sign={:?}, buf={}KB, streams={}]",
183 self.tier,
184 self.cipher,
185 self.pq_kem,
186 self.pq_sign,
187 self.buffer_size / 1024,
188 self.max_streams,
189 )
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn constrained_profile() {
199 let p = DeviceProfile::constrained();
200 assert_eq!(p.tier, DeviceTier::Constrained);
201 assert_eq!(p.cipher, CipherSuite::ChaCha20Poly1305);
202 assert_eq!(p.pq_kem, PqKemLevel::Kyber512);
203 assert_eq!(p.pq_sign, PqSignLevel::Dilithium2);
204 assert_eq!(p.buffer_size, 2048);
205 assert!(!p.coalescing);
206 assert!(!p.compression);
207 eprintln!("Constrained: {}", p);
208 }
209
210 #[test]
211 fn standard_profile() {
212 let p = DeviceProfile::standard();
213 assert_eq!(p.tier, DeviceTier::Standard);
214 assert_eq!(p.pq_kem, PqKemLevel::Kyber768);
215 assert!(p.coalescing);
216 assert!(p.compression);
217 eprintln!("Standard: {}", p);
218 }
219
220 #[test]
221 fn performance_profile() {
222 let p = DeviceProfile::performance();
223 assert_eq!(p.tier, DeviceTier::Performance);
224 assert_eq!(p.cipher, CipherSuite::Aes256Gcm);
225 assert_eq!(p.pq_kem, PqKemLevel::Kyber768);
226 assert_eq!(p.buffer_size, 65536);
227 eprintln!("Performance: {}", p);
228 }
229
230 #[test]
231 fn auto_detect_profile() {
232 let p = DeviceProfile::auto_detect();
233 eprintln!("Auto: {}", p);
234 #[cfg(target_pointer_width = "64")]
236 assert_eq!(p.tier, DeviceTier::Performance);
237 }
238
239 #[test]
240 fn all_tiers_have_pq() {
241 for tier in [
242 DeviceTier::Constrained,
243 DeviceTier::Standard,
244 DeviceTier::Performance,
245 ] {
246 let p = DeviceProfile::for_tier(tier, &HwCaps::detect());
247 assert!(matches!(
249 p.pq_kem,
250 PqKemLevel::Kyber512 | PqKemLevel::Kyber768
251 ));
252 assert!(matches!(
254 p.pq_sign,
255 PqSignLevel::Dilithium2 | PqSignLevel::Dilithium3
256 ));
257 eprintln!("{:?}: PQ KEM={:?}, PQ Sign={:?}", tier, p.pq_kem, p.pq_sign);
258 }
259 }
260}