Skip to main content

lib_q_core/wasm/
providers.rs

1//! WASM-compatible provider bindings
2//!
3//! This module provides WASM-compatible bindings for cryptographic providers,
4//! integrating with the new modular architecture and security validation system.
5
6#[cfg(feature = "wasm")]
7extern crate alloc;
8#[cfg(feature = "wasm")]
9use alloc::{
10    string::{
11        String,
12        ToString,
13    },
14    vec::Vec,
15};
16
17#[cfg(feature = "wasm")]
18// use js_sys::Uint8Array;
19use serde_json;
20#[cfg(feature = "wasm")]
21use wasm_bindgen::prelude::*;
22
23use crate::api::{
24    Algorithm,
25    AlgorithmCategory,
26    CryptoProvider,
27};
28// use crate::error::Result;
29use crate::providers::LibQCryptoProvider;
30use crate::security::SecurityValidator;
31
32/// WASM-compatible provider manager
33///
34/// This manager provides JavaScript-compatible bindings for provider operations:
35/// - Integrates with the new modular architecture
36/// - Includes security validation
37/// - Provides consistent error handling
38/// - Supports all provider operations
39#[cfg_attr(feature = "wasm", wasm_bindgen)]
40pub struct WasmProviderManager {
41    provider: LibQCryptoProvider,
42    security_validator: SecurityValidator,
43}
44
45impl WasmProviderManager {
46    /// Create a new WASM provider manager
47    pub fn new() -> WasmProviderManager {
48        WasmProviderManager {
49            provider: LibQCryptoProvider::new()
50                .unwrap_or_else(|_| LibQCryptoProvider::new().unwrap()),
51            security_validator: SecurityValidator::new()
52                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
53        }
54    }
55}
56
57impl Default for WasmProviderManager {
58    fn default() -> Self {
59        Self::new()
60    }
61}
62
63impl WasmProviderManager {
64    /// Get provider information
65    pub fn get_provider_info(&self) -> String {
66        #[cfg(feature = "wasm")]
67        {
68            serde_json::json!({
69                "name": "lib-Q Crypto Provider",
70                "version": crate::VERSION,
71                "description": "Post-Quantum Cryptography Provider",
72                "features": {
73                    "kem": true,
74                    "signature": true,
75                    "hash": true,
76                    "aead": true,
77                    "security_hardened": true,
78                    "post_quantum": true
79                },
80                "security_levels": [128, 192, 256],
81                "algorithms": {
82                    "kem": self.get_kem_algorithms(),
83                    "signature": self.get_signature_algorithms(),
84                    "hash": self.get_hash_algorithms(),
85                    "aead": self.get_aead_algorithms()
86                }
87            })
88            .to_string()
89        }
90        #[cfg(not(feature = "wasm"))]
91        {
92            "{}".to_string()
93        }
94    }
95
96    /// Check if an algorithm is supported
97    pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
98        // First check if it's a valid algorithm name
99        let algorithm = match self.parse_algorithm(algorithm) {
100            Ok(alg) => alg,
101            Err(_) => return false,
102        };
103
104        // Then check if the provider actually supports this algorithm
105        match algorithm.category() {
106            AlgorithmCategory::Kem => self.provider.kem().is_some(),
107            AlgorithmCategory::Signature => self.provider.signature().is_some(),
108            AlgorithmCategory::Hash => self.provider.hash().is_some(),
109            AlgorithmCategory::Aead => self.provider.aead().is_some(),
110            AlgorithmCategory::PrivacyProtocol => false,
111        }
112    }
113
114    /// Get algorithm information
115    pub fn get_algorithm_info(&self, algorithm: &str) -> Result<JsValue, JsValue> {
116        let algorithm = self.parse_algorithm(algorithm)?;
117
118        #[cfg(feature = "wasm")]
119        {
120            let info = serde_json::json!({
121                "name": algorithm.to_string(),
122                "category": algorithm.category().to_string(),
123                "security_level": 256, // Placeholder
124                "key_sizes": {
125                    "public_key": 1024, // Placeholder
126                    "secret_key": 1024, // Placeholder
127                    "signature": 1024, // Placeholder
128                    "nonce": 12, // Placeholder
129                    "key": 32 // Placeholder
130                },
131                "message_limits": {
132                    "max_size": 1024 * 1024 // Placeholder
133                },
134                "features": {
135                    "kem": algorithm.category() == AlgorithmCategory::Kem,
136                    "signature": algorithm.category() == AlgorithmCategory::Signature,
137                    "hash": algorithm.category() == AlgorithmCategory::Hash,
138                    "aead": algorithm.category() == AlgorithmCategory::Aead,
139                    "privacy_protocol": algorithm.category() == AlgorithmCategory::PrivacyProtocol
140                }
141            });
142
143            match serde_wasm_bindgen::to_value(&info) {
144                Ok(value) => Ok(value),
145                Err(_) => Err(JsValue::from_str("Serialization error")),
146            }
147        }
148        #[cfg(not(feature = "wasm"))]
149        {
150            Err(JsValue::from_str("WASM feature not enabled"))
151        }
152    }
153
154    /// Get all supported algorithms
155    pub fn get_all_algorithms(&self) -> String {
156        #[cfg(feature = "wasm")]
157        {
158            let algorithms = serde_json::json!({
159                "kem": self.get_kem_algorithms(),
160                "signature": self.get_signature_algorithms(),
161                "hash": self.get_hash_algorithms(),
162                "aead": self.get_aead_algorithms()
163            });
164            algorithms.to_string()
165        }
166        #[cfg(not(feature = "wasm"))]
167        {
168            "{}".to_string()
169        }
170    }
171
172    /// Get KEM algorithms
173    pub fn get_kem_algorithms(&self) -> Vec<String> {
174        #[allow(unused_mut)] // mut needed when feature flags are enabled
175        let mut algorithms = alloc::vec![
176            "ml-kem-512".to_string(),
177            "ml-kem-768".to_string(),
178            "ml-kem-1024".to_string(),
179        ];
180
181        algorithms
182    }
183
184    /// Get signature algorithms
185    pub fn get_signature_algorithms(&self) -> Vec<String> {
186        crate::wasm::conversions::WASM_SIGNATURE_ALGORITHM_IDS
187            .iter()
188            .map(|s| (*s).to_string())
189            .collect()
190    }
191
192    /// Get hash algorithms
193    pub fn get_hash_algorithms(&self) -> Vec<String> {
194        alloc::vec![
195            "sha3-224".to_string(),
196            "sha3-256".to_string(),
197            "sha3-384".to_string(),
198            "sha3-512".to_string(),
199            "shake128".to_string(),
200            "shake256".to_string(),
201        ]
202    }
203
204    /// Get AEAD algorithms
205    pub fn get_aead_algorithms(&self) -> Vec<String> {
206        let algorithms = alloc::vec!["saturnin".to_string(), "shake256-aead".to_string(),];
207
208        algorithms
209    }
210
211    /// Validate algorithm parameters
212    pub fn validate_algorithm_params(
213        &self,
214        algorithm: &str,
215        key_size: Option<usize>,
216        message_size: Option<usize>,
217        nonce_size: Option<usize>,
218    ) -> Result<bool, JsValue> {
219        let algorithm = self.parse_algorithm(algorithm)?;
220
221        // Use security validator for comprehensive validation
222        if let Some(size) = key_size {
223            if size == 0 {
224                return Err(JsValue::from_str("Invalid algorithm key: empty key"));
225            }
226            // Validate key size against algorithm requirements
227            let test_key = (0..size).map(|_| 0u8).collect::<Vec<u8>>();
228            self.security_validator
229                .validate_key_size(algorithm, &test_key, true)
230                .map_err(crate::wasm::error::error_to_js_value)?;
231        }
232
233        if let Some(size) = message_size {
234            if size == 0 {
235                return Err(JsValue::from_str("Invalid message size: empty data"));
236            }
237            // Validate message size against the limit that applies to this algorithm family.
238            let test_message = (0..size).map(|_| 0u8).collect::<Vec<u8>>();
239            if algorithm.supports_category(AlgorithmCategory::Aead) {
240                self.security_validator
241                    .validate_aead_message(&test_message)
242                    .map_err(crate::wasm::error::error_to_js_value)?;
243            } else {
244                self.security_validator
245                    .validate_hash_input(&test_message)
246                    .map_err(crate::wasm::error::error_to_js_value)?;
247            }
248        }
249
250        if let Some(size) = nonce_size {
251            if size == 0 {
252                return Err(JsValue::from_str("Invalid nonce size: empty nonce"));
253            }
254            // Validate nonce size
255            let test_nonce = (0..size).map(|_| 0u8).collect::<Vec<u8>>();
256            self.security_validator
257                .validate_nonce(&test_nonce)
258                .map_err(crate::wasm::error::error_to_js_value)?;
259        }
260
261        Ok(true)
262    }
263
264    /// Get security recommendations
265    pub fn get_security_recommendations(&self) -> String {
266        #[cfg(feature = "wasm")]
267        {
268            serde_json::json!({
269                "general": {
270                    "use_authenticated_encryption": true,
271                    "validate_all_inputs": true,
272                    "use_secure_random": true,
273                    "protect_secret_keys": true,
274                    "rotate_keys_regularly": true
275                },
276                "kem": {
277                    "recommended_algorithms": ["ml-kem-768", "ml-kem-1024"],
278                    "key_rotation": "Every 90 days",
279                    "security_level": "Minimum 192-bit"
280                },
281                "signature": {
282                    "recommended_algorithms": ["ml-dsa-65", "ml-dsa-87"],
283                    "key_rotation": "Every 90 days",
284                    "security_level": "Minimum 192-bit"
285                },
286                "hash": {
287                    "recommended_algorithms": ["sha3-256", "sha3-384"],
288                    "security_level": "Minimum 256-bit"
289                },
290                "aead": {
291                    "recommended_algorithms": ["saturnin", "shake256-aead"],
292                    "nonce_requirements": "Unique per key",
293                    "security_level": "Minimum 256-bit"
294                }
295            })
296            .to_string()
297        }
298        #[cfg(not(feature = "wasm"))]
299        {
300            "{}".to_string()
301        }
302    }
303
304    /// Get performance benchmarks
305    pub fn get_performance_benchmarks(&self) -> String {
306        #[cfg(feature = "wasm")]
307        {
308            serde_json::json!({
309                "note": "Performance benchmarks are environment-dependent",
310                "recommendations": {
311                    "kem": {
312                        "fastest": "ml-kem-512",
313                        "most_secure": "ml-kem-1024",
314                        "balanced": "ml-kem-768"
315                    },
316                    "signature": {
317                        "fastest": "ml-dsa-44",
318                        "most_secure": "ml-dsa-87",
319                        "balanced": "ml-dsa-65"
320                    },
321                    "hash": {
322                        "fastest": "sha3-224",
323                        "most_secure": "sha3-512",
324                        "balanced": "sha3-256"
325                    }
326                }
327            })
328            .to_string()
329        }
330        #[cfg(not(feature = "wasm"))]
331        {
332            "{}".to_string()
333        }
334    }
335
336    /// Parse algorithm from string
337    fn parse_algorithm(&self, algorithm: &str) -> Result<Algorithm, crate::error::Error> {
338        crate::wasm::error::parse_algorithm_wasm(algorithm).map_err(|_| {
339            crate::error::Error::InvalidAlgorithm {
340                algorithm: "Invalid algorithm name",
341            }
342        })
343    }
344}
345
346/// WASM-compatible provider factory
347///
348/// This factory provides JavaScript-compatible bindings for creating providers:
349/// - Integrates with the new modular architecture
350/// - Provides consistent error handling
351/// - Supports all provider creation operations
352#[cfg_attr(feature = "wasm", wasm_bindgen)]
353pub struct WasmProviderFactory;
354
355#[cfg_attr(feature = "wasm", wasm_bindgen)]
356impl WasmProviderFactory {
357    /// Create a new provider manager
358    #[cfg_attr(feature = "wasm", wasm_bindgen)]
359    pub fn create_provider_manager() -> WasmProviderManager {
360        WasmProviderManager::new()
361    }
362
363    /// Create a provider manager with specific configuration
364    #[cfg_attr(feature = "wasm", wasm_bindgen)]
365    pub fn create_provider_manager_with_config(
366        config: &str,
367    ) -> Result<WasmProviderManager, JsValue> {
368        #[cfg(feature = "wasm")]
369        {
370            // Parse configuration (simplified for now)
371            let _config: serde_json::Value = match serde_json::from_str(config) {
372                Ok(config) => config,
373                Err(_) => {
374                    return Err(JsValue::from_str("Configuration parsing error"));
375                }
376            };
377
378            // For now, just create a default provider manager
379            // In a real implementation, this would configure the provider based on the config
380            Ok(WasmProviderManager::new())
381        }
382        #[cfg(not(feature = "wasm"))]
383        {
384            Err(JsValue::from_str("WASM feature not enabled"))
385        }
386    }
387
388    /// Get available provider types
389    #[cfg_attr(feature = "wasm", wasm_bindgen)]
390    pub fn get_available_providers() -> String {
391        #[cfg(feature = "wasm")]
392        {
393            serde_json::json!({
394                "providers": [
395                    {
396                        "name": "lib-q-crypto",
397                        "description": "Default lib-Q cryptographic provider",
398                        "features": ["kem", "signature", "hash", "aead"],
399                        "security_levels": [128, 192, 256]
400                    }
401                ]
402            })
403            .to_string()
404        }
405        #[cfg(not(feature = "wasm"))]
406        {
407            "{}".to_string()
408        }
409    }
410
411    /// Validate provider configuration
412    #[cfg_attr(feature = "wasm", wasm_bindgen)]
413    pub fn validate_provider_config(config: &str) -> Result<bool, JsValue> {
414        #[cfg(feature = "wasm")]
415        {
416            let _config: serde_json::Value = match serde_json::from_str(config) {
417                Ok(config) => config,
418                Err(_) => {
419                    return Err(JsValue::from_str("Configuration parsing error"));
420                }
421            };
422
423            // Basic validation - in a real implementation, this would be more comprehensive
424            Ok(true)
425        }
426        #[cfg(not(feature = "wasm"))]
427        {
428            Err(JsValue::from_str("WASM feature not enabled"))
429        }
430    }
431}
432
433#[cfg(test)]
434mod tests {
435
436    #[test]
437    #[cfg(target_arch = "wasm32")]
438    fn test_wasm_provider_manager_creation() {
439        let manager = WasmProviderManager::new();
440        let info = manager.get_provider_info();
441        assert!(info.contains("lib-Q") || info == "{}");
442    }
443
444    #[test]
445    #[cfg(target_arch = "wasm32")]
446    fn test_wasm_provider_factory() {
447        let manager = WasmProviderFactory::create_provider_manager();
448        assert!(manager.is_algorithm_supported("sha3-256"));
449    }
450
451    #[test]
452    #[cfg(target_arch = "wasm32")]
453    fn test_algorithm_support() {
454        let manager = WasmProviderManager::new();
455        assert!(manager.is_algorithm_supported("sha3-256"));
456        assert!(!manager.is_algorithm_supported("invalid-algorithm"));
457    }
458
459    #[test]
460    #[cfg(target_arch = "wasm32")]
461    fn test_algorithm_info() {
462        let manager = WasmProviderManager::new();
463        let info = manager.get_algorithm_info("sha3-256");
464        assert!(info.is_ok());
465    }
466
467    #[test]
468    #[cfg(target_arch = "wasm32")]
469    fn test_security_recommendations() {
470        let manager = WasmProviderManager::new();
471        let recommendations = manager.get_security_recommendations();
472        assert!(
473            recommendations.contains("use_authenticated_encryption") || recommendations == "{}"
474        );
475    }
476}