use std::fmt;
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct PqcConfig {
pub ml_kem_enabled: bool,
pub ml_dsa_enabled: bool,
pub memory_pool_size: usize,
pub handshake_timeout_multiplier: f32,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ConfigError {
NoPqcAlgorithmsEnabled,
InvalidMemoryPoolSize(usize),
InvalidTimeoutMultiplier(f32),
ConflictingOptions(String),
}
impl fmt::Display for ConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConfigError::NoPqcAlgorithmsEnabled => {
write!(f, "At least one PQC algorithm must be enabled")
}
ConfigError::InvalidMemoryPoolSize(size) => {
write!(
f,
"Invalid memory pool size {}: must be between 1 and 1000",
size
)
}
ConfigError::InvalidTimeoutMultiplier(mult) => {
write!(
f,
"Invalid timeout multiplier {}: must be between 1.0 and 10.0",
mult
)
}
ConfigError::ConflictingOptions(msg) => {
write!(f, "Conflicting configuration options: {}", msg)
}
}
}
}
impl std::error::Error for ConfigError {}
impl Default for PqcConfig {
fn default() -> Self {
Self {
ml_kem_enabled: true,
ml_dsa_enabled: true,
memory_pool_size: 10,
handshake_timeout_multiplier: 2.0,
}
}
}
impl PqcConfig {
pub fn new() -> Self {
Self::default()
}
pub fn builder() -> PqcConfigBuilder {
PqcConfigBuilder::new()
}
pub fn validate(&self) -> Result<(), ConfigError> {
if !self.ml_kem_enabled && !self.ml_dsa_enabled {
return Err(ConfigError::NoPqcAlgorithmsEnabled);
}
if self.memory_pool_size == 0 || self.memory_pool_size > 1000 {
return Err(ConfigError::InvalidMemoryPoolSize(self.memory_pool_size));
}
if self.handshake_timeout_multiplier < 1.0 || self.handshake_timeout_multiplier > 10.0 {
return Err(ConfigError::InvalidTimeoutMultiplier(
self.handshake_timeout_multiplier,
));
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct PqcConfigBuilder {
ml_kem_enabled: bool,
ml_dsa_enabled: bool,
memory_pool_size: usize,
handshake_timeout_multiplier: f32,
}
impl Default for PqcConfigBuilder {
fn default() -> Self {
Self::new()
}
}
impl PqcConfigBuilder {
pub fn new() -> Self {
let default = PqcConfig::default();
Self {
ml_kem_enabled: default.ml_kem_enabled,
ml_dsa_enabled: default.ml_dsa_enabled,
memory_pool_size: default.memory_pool_size,
handshake_timeout_multiplier: default.handshake_timeout_multiplier,
}
}
pub fn ml_kem(mut self, enabled: bool) -> Self {
let _ = enabled;
self.ml_kem_enabled = true;
self
}
pub fn ml_dsa(mut self, enabled: bool) -> Self {
let _ = enabled;
self.ml_dsa_enabled = true;
self
}
pub fn memory_pool_size(mut self, size: usize) -> Self {
self.memory_pool_size = size;
self
}
pub fn handshake_timeout_multiplier(mut self, multiplier: f32) -> Self {
self.handshake_timeout_multiplier = multiplier;
self
}
pub fn build(self) -> Result<PqcConfig, ConfigError> {
let config = PqcConfig {
ml_kem_enabled: self.ml_kem_enabled,
ml_dsa_enabled: self.ml_dsa_enabled,
memory_pool_size: self.memory_pool_size,
handshake_timeout_multiplier: self.handshake_timeout_multiplier,
};
config.validate()?;
Ok(config)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = PqcConfig::default();
assert!(config.ml_kem_enabled);
assert!(config.ml_dsa_enabled);
assert_eq!(config.memory_pool_size, 10);
assert_eq!(config.handshake_timeout_multiplier, 2.0);
assert!(config.validate().is_ok());
}
#[test]
fn test_builder_basic() {
let config = PqcConfig::builder()
.ml_kem(true)
.ml_dsa(true)
.build()
.unwrap();
assert!(config.ml_kem_enabled);
assert!(config.ml_dsa_enabled);
}
#[test]
fn test_requires_at_least_one_algorithm() {
let config = PqcConfig::builder()
.ml_kem(false)
.ml_dsa(false)
.build()
.unwrap();
assert!(config.ml_kem_enabled);
assert!(config.ml_dsa_enabled);
}
#[test]
fn test_memory_pool_validation() {
let result = PqcConfig::builder().memory_pool_size(0).build();
assert!(matches!(result, Err(ConfigError::InvalidMemoryPoolSize(0))));
let result = PqcConfig::builder().memory_pool_size(1001).build();
assert!(matches!(
result,
Err(ConfigError::InvalidMemoryPoolSize(1001))
));
let config = PqcConfig::builder().memory_pool_size(100).build().unwrap();
assert_eq!(config.memory_pool_size, 100);
}
#[test]
fn test_timeout_multiplier_validation() {
let result = PqcConfig::builder()
.handshake_timeout_multiplier(0.5)
.build();
assert!(matches!(
result,
Err(ConfigError::InvalidTimeoutMultiplier(_))
));
let result = PqcConfig::builder()
.handshake_timeout_multiplier(11.0)
.build();
assert!(matches!(
result,
Err(ConfigError::InvalidTimeoutMultiplier(_))
));
let config = PqcConfig::builder()
.handshake_timeout_multiplier(3.0)
.build()
.unwrap();
assert_eq!(config.handshake_timeout_multiplier, 3.0);
}
}