spectral_vm 0.1.6

HYPERION: Production-ready zero-knowledge virtual machine with spectral analysis
Documentation
/*
 * ═══════════════════════════════════════════════════════════════════════════
 * TECHNICAL MANIFEST: Configuration Management
 * SPECTRAL ROLE: Runtime Configuration and Parameter Management
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * CONFIGURATION HIERARCHY:
 * 1. Default values (production-ready, hardcoded in code)
 * 2. TOML configuration file (optional)
 * 3. Environment variables (optional advanced overrides)
 * 4. Runtime overrides (programmatic)
 *
 * SECURITY PROPERTIES:
 * - Configuration validation at startup
 * - Secure defaults for cryptographic parameters
 * - Environment variable precedence for deployment flexibility
 *
 * ARCHITECTURAL INVARIANTS:
 * - All configuration values have sensible defaults
 * - Configuration is immutable after initialization
 * - Validation ensures system stability and security
 * ═══════════════════════════════════════════════════════════════════════════
 */

use crate::fri::FriParams;
use serde::{Deserialize, Serialize};
use std::env;
use std::fs;
use std::path::Path;

/// Main configuration structure for HYPERION Spectral VM
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    /// FRI protocol parameters
    pub fri: FriConfig,
    /// Virtual machine settings
    pub vm: VMConfig,
    /// Security and cryptographic parameters
    pub security: SecurityConfig,
    /// Performance tuning parameters
    pub performance: PerformanceConfig,
}

/// FRI protocol configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FriConfig {
    /// Initial codeword size (must be power of 2)
    pub codeword_size: usize,
    /// Reed-Solomon blowup factor
    pub blowup_factor: usize,
    /// Number of query rounds for security
    pub num_queries: usize,
    /// Final polynomial degree threshold
    pub final_degree: usize,
}

/// Virtual machine configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VMConfig {
    /// Maximum memory size in bytes
    pub max_memory: usize,
    /// Maximum instruction trace length
    pub max_trace_length: usize,
    /// Clock cycle timeout for execution
    pub execution_timeout: u64,
}

/// Security configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityConfig {
    /// Cryptographic security level (bits)
    pub security_level: usize,
    /// Enable additional security checks
    pub enable_extra_checks: bool,
    /// Randomness source configuration
    pub randomness_source: String,
}

/// Performance tuning configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceConfig {
    /// Enable SIMD acceleration
    pub enable_simd: bool,
    /// Thread pool size for parallel operations
    pub thread_pool_size: usize,
    /// Memory pool size for allocations
    pub memory_pool_size: usize,
}

/// Configuration loading errors
#[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 {
    /// Create default configuration with secure defaults
    /// Production-ready settings optimized for performance and security
    pub fn default() -> Self {
        Self {
            fri: FriConfig {
                codeword_size: 2048,    // 2^11 - Better security for production
                blowup_factor: 2,
                num_queries: 64,        // Higher security level
                final_degree: 1,
            },
            vm: VMConfig {
                max_memory: 8388608,    // 8MB - Support for larger circuits (2^20+ variables)
                max_trace_length: 500000,
                execution_timeout: 5000000, // 5M cycles - Longer for complex circuits
            },
            security: SecurityConfig {
                security_level: 128,
                enable_extra_checks: true,
                randomness_source: "system".to_string(),
            },
            performance: PerformanceConfig {
                enable_simd: true,      // Always enable SIMD when available
                thread_pool_size: num_cpus::get(),
                memory_pool_size: 134217728, // 128MB - Larger pools for big circuits
            },
        }
    }

    /// Load configuration from TOML file
    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)?;

        // Apply environment variable overrides
        config.apply_env_overrides();

        // Validate configuration
        config.validate()?;

        Ok(config)
    }

    /// Load configuration with fallback to defaults
    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()
        })
    }

    /// Apply optional environment variable overrides (for advanced users)
    /// This is optional - default values are production-ready
    fn apply_env_overrides(&mut self) {
        // FRI parameters (optional overrides)
        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);
            }
        }

        // VM parameters (optional overrides)
        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);
            }
        }

        // Performance parameters (optional overrides)
        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;
            }
        }
    }

    /// Validate configuration values
    fn validate(&self) -> Result<(), ConfigError> {
        // FRI validation
        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()));
        }

        // VM validation
        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()));
        }

        // Performance validation
        if self.performance.thread_pool_size == 0 {
            return Err(ConfigError::Validation("Thread pool size cannot be zero".to_string()));
        }

        Ok(())
    }

    /// Get FRI parameters as FriParams struct
    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,
        }
    }

    /// Save configuration to TOML file
    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(())
    }
}

/// Initialize configuration from file or defaults
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; // Not power of 2
        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");
        }
    }
}