use crate::fri::FriParams;
use serde::{Deserialize, Serialize};
use std::env;
use std::fs;
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub fri: FriConfig,
pub vm: VMConfig,
pub security: SecurityConfig,
pub performance: PerformanceConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FriConfig {
pub codeword_size: usize,
pub blowup_factor: usize,
pub num_queries: usize,
pub final_degree: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VMConfig {
pub max_memory: usize,
pub max_trace_length: usize,
pub execution_timeout: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityConfig {
pub security_level: usize,
pub enable_extra_checks: bool,
pub randomness_source: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceConfig {
pub enable_simd: bool,
pub thread_pool_size: usize,
pub memory_pool_size: usize,
}
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("TOML parsing error: {0}")]
Toml(#[from] toml::de::Error),
#[error("TOML serialization error: {0}")]
TomlSer(#[from] toml::ser::Error),
#[error("Validation error: {0}")]
Validation(String),
}
impl Config {
pub fn default() -> Self {
Self {
fri: FriConfig {
codeword_size: 2048, blowup_factor: 2,
num_queries: 64, final_degree: 1,
},
vm: VMConfig {
max_memory: 8388608, max_trace_length: 500000,
execution_timeout: 5000000, },
security: SecurityConfig {
security_level: 128,
enable_extra_checks: true,
randomness_source: "system".to_string(),
},
performance: PerformanceConfig {
enable_simd: true, thread_pool_size: num_cpus::get(),
memory_pool_size: 134217728, },
}
}
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, ConfigError> {
let content = fs::read_to_string(path)?;
let mut config: Self = toml::from_str(&content)?;
config.apply_env_overrides();
config.validate()?;
Ok(config)
}
pub fn load_or_default<P: AsRef<Path>>(path: P) -> Self {
Self::from_file(path).unwrap_or_else(|_| {
tracing::warn!("Warning: Failed to load config, using defaults");
Self::default()
})
}
fn apply_env_overrides(&mut self) {
if let Ok(val) = env::var("HYPERION_FRI_CODEWORD_SIZE") {
if let Ok(size) = val.parse() {
self.fri.codeword_size = size;
tracing::info!("FRI codeword size override: {}", size);
}
}
if let Ok(val) = env::var("HYPERION_FRI_NUM_QUERIES") {
if let Ok(queries) = val.parse() {
self.fri.num_queries = queries;
tracing::info!("FRI queries override: {}", queries);
}
}
if let Ok(val) = env::var("HYPERION_VM_MAX_MEMORY") {
if let Ok(mem) = val.parse() {
self.vm.max_memory = mem;
tracing::info!("VM memory override: {} bytes", mem);
}
}
if let Ok(val) = env::var("HYPERION_PERF_SIMD") {
self.performance.enable_simd = val.to_lowercase() == "true";
tracing::info!("SIMD override: {}", self.performance.enable_simd);
}
if let Ok(val) = env::var("HYPERION_PERF_THREADS") {
if let Ok(threads) = val.parse() {
self.performance.thread_pool_size = threads;
}
}
}
fn validate(&self) -> Result<(), ConfigError> {
if !self.fri.codeword_size.is_power_of_two() {
return Err(ConfigError::Validation("FRI codeword size must be power of 2".to_string()));
}
if self.fri.codeword_size < 256 {
return Err(ConfigError::Validation("FRI codeword size too small".to_string()));
}
if self.fri.num_queries < 10 {
return Err(ConfigError::Validation("Too few FRI queries for security".to_string()));
}
if self.vm.max_memory < 1024 {
return Err(ConfigError::Validation("VM memory too small".to_string()));
}
if self.vm.max_trace_length < 100 {
return Err(ConfigError::Validation("VM trace length too small".to_string()));
}
if self.performance.thread_pool_size == 0 {
return Err(ConfigError::Validation("Thread pool size cannot be zero".to_string()));
}
Ok(())
}
pub fn fri_params(&self) -> FriParams {
FriParams {
codeword_size: self.fri.codeword_size,
blowup_factor: self.fri.blowup_factor,
num_queries: self.fri.num_queries,
final_degree: self.fri.final_degree,
}
}
pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<(), ConfigError> {
let toml = toml::to_string_pretty(self)?;
fs::write(path, toml)?;
Ok(())
}
}
pub fn init_config<P: AsRef<Path>>(config_path: Option<P>) -> Config {
if let Some(path) = config_path {
Config::from_file(path).unwrap_or_else(|e| {
tracing::warn!("Failed to load config: {}, using defaults", e);
Config::default()
})
} else {
Config::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = Config::default();
assert_eq!(config.fri.codeword_size, 1024);
assert_eq!(config.vm.max_memory, 1048576);
assert!(config.performance.enable_simd);
}
#[test]
fn test_config_validation() {
let mut config = Config::default();
config.fri.codeword_size = 100; assert!(config.validate().is_err());
}
#[test]
fn test_env_override() {
unsafe {
env::set_var("HYPERION_FRI_NUM_QUERIES", "64");
}
let mut config = Config::default();
config.apply_env_overrides();
assert_eq!(config.fri.num_queries, 64);
unsafe {
env::remove_var("HYPERION_FRI_NUM_QUERIES");
}
}
}