use crate::crypto::adaptive_crypto::{CipherSuite, HwCaps};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeviceTier {
Constrained,
Standard,
Performance,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PqKemLevel {
Kyber512,
Kyber768,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PqSignLevel {
Dilithium2,
Dilithium3,
}
#[derive(Debug, Clone)]
pub struct DeviceProfile {
pub tier: DeviceTier,
pub cipher: CipherSuite,
pub pq_kem: PqKemLevel,
pub pq_sign: PqSignLevel,
pub buffer_size: usize,
pub max_streams: u16,
pub coalescing: bool,
pub max_datagram_size: usize,
pub compression: bool,
pub max_payload: usize,
}
impl DeviceProfile {
pub fn auto_detect() -> Self {
let caps = HwCaps::detect();
let available_ram = Self::estimate_available_ram();
let tier = if available_ram < 1_048_576 {
DeviceTier::Constrained
} else if available_ram < 512_000_000 {
DeviceTier::Standard
} else {
DeviceTier::Performance
};
Self::for_tier(tier, &caps)
}
pub fn for_tier(tier: DeviceTier, caps: &HwCaps) -> Self {
match tier {
DeviceTier::Constrained => Self {
tier,
cipher: CipherSuite::ChaCha20Poly1305, pq_kem: PqKemLevel::Kyber512, pq_sign: PqSignLevel::Dilithium2, buffer_size: 2 * 1024, max_streams: 4,
coalescing: false, max_datagram_size: 512, compression: false, max_payload: 256,
},
DeviceTier::Standard => Self {
tier,
cipher: caps.recommended_cipher(), pq_kem: PqKemLevel::Kyber768, pq_sign: PqSignLevel::Dilithium3, buffer_size: 16 * 1024, max_streams: 64,
coalescing: true,
max_datagram_size: 4096,
compression: true, max_payload: 1400, },
DeviceTier::Performance => Self {
tier,
cipher: CipherSuite::Aes256Gcm, pq_kem: PqKemLevel::Kyber768, pq_sign: PqSignLevel::Dilithium3, buffer_size: 64 * 1024, max_streams: 256,
coalescing: true,
max_datagram_size: 8192, compression: true, max_payload: 8192,
},
}
}
pub fn constrained() -> Self {
Self::for_tier(DeviceTier::Constrained, &HwCaps { has_hw_aes: false })
}
pub fn standard() -> Self {
Self::for_tier(DeviceTier::Standard, &HwCaps::detect())
}
pub fn performance() -> Self {
Self::for_tier(DeviceTier::Performance, &HwCaps { has_hw_aes: true })
}
fn estimate_available_ram() -> usize {
#[cfg(target_pointer_width = "64")]
{
8_000_000_000
}
#[cfg(target_pointer_width = "32")]
{
512_000
}
#[cfg(not(any(target_pointer_width = "64", target_pointer_width = "32")))]
{
256_000
} }
pub fn is_full_pq(&self) -> bool {
matches!(self.pq_kem, PqKemLevel::Kyber768)
}
pub fn tier_byte(&self) -> u8 {
match self.tier {
DeviceTier::Constrained => 0,
DeviceTier::Standard => 1,
DeviceTier::Performance => 2,
}
}
}
impl std::fmt::Display for DeviceProfile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{:?} [cipher={:?}, kem={:?}, sign={:?}, buf={}KB, streams={}]",
self.tier,
self.cipher,
self.pq_kem,
self.pq_sign,
self.buffer_size / 1024,
self.max_streams,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn constrained_profile() {
let p = DeviceProfile::constrained();
assert_eq!(p.tier, DeviceTier::Constrained);
assert_eq!(p.cipher, CipherSuite::ChaCha20Poly1305);
assert_eq!(p.pq_kem, PqKemLevel::Kyber512);
assert_eq!(p.pq_sign, PqSignLevel::Dilithium2);
assert_eq!(p.buffer_size, 2048);
assert!(!p.coalescing);
assert!(!p.compression);
eprintln!("Constrained: {}", p);
}
#[test]
fn standard_profile() {
let p = DeviceProfile::standard();
assert_eq!(p.tier, DeviceTier::Standard);
assert_eq!(p.pq_kem, PqKemLevel::Kyber768);
assert!(p.coalescing);
assert!(p.compression);
eprintln!("Standard: {}", p);
}
#[test]
fn performance_profile() {
let p = DeviceProfile::performance();
assert_eq!(p.tier, DeviceTier::Performance);
assert_eq!(p.cipher, CipherSuite::Aes256Gcm);
assert_eq!(p.pq_kem, PqKemLevel::Kyber768);
assert_eq!(p.buffer_size, 65536);
eprintln!("Performance: {}", p);
}
#[test]
fn auto_detect_profile() {
let p = DeviceProfile::auto_detect();
eprintln!("Auto: {}", p);
#[cfg(target_pointer_width = "64")]
assert_eq!(p.tier, DeviceTier::Performance);
}
#[test]
fn all_tiers_have_pq() {
for tier in [
DeviceTier::Constrained,
DeviceTier::Standard,
DeviceTier::Performance,
] {
let p = DeviceProfile::for_tier(tier, &HwCaps::detect());
assert!(matches!(
p.pq_kem,
PqKemLevel::Kyber512 | PqKemLevel::Kyber768
));
assert!(matches!(
p.pq_sign,
PqSignLevel::Dilithium2 | PqSignLevel::Dilithium3
));
eprintln!("{:?}: PQ KEM={:?}, PQ Sign={:?}", tier, p.pq_kem, p.pq_sign);
}
}
}