Skip to main content

lib_q_core/wasm/
contexts.rs

1//! WASM-compatible context wrappers
2//!
3//! This module provides WASM-compatible wrappers for all cryptographic contexts,
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    boxed::Box,
11    format,
12    string::{
13        String,
14        ToString,
15    },
16    vec::Vec,
17};
18
19#[cfg(feature = "wasm")]
20use js_sys::Uint8Array;
21#[cfg(feature = "wasm")]
22use serde_json;
23#[cfg(feature = "wasm")]
24use serde_wasm_bindgen;
25#[cfg(feature = "wasm")]
26use wasm_bindgen::prelude::*;
27
28use crate::api::{
29    Algorithm,
30    AlgorithmCategory,
31};
32use crate::contexts::{
33    AeadContext,
34    HashContext,
35    KemContext,
36    SignatureContext,
37};
38// use crate::error::Result;
39use crate::providers::LibQCryptoProvider;
40use crate::security::SecurityValidator;
41use crate::traits::{
42    AeadKey,
43    Nonce,
44};
45// Import secure error handling
46use crate::wasm::conversions::WASM_SIGNATURE_ALGORITHM_IDS;
47use crate::wasm::error::{
48    convert_result,
49    error_to_js_value,
50    parse_algorithm_wasm,
51    // secure_serialize,
52};
53
54/// WASM-compatible KEM context wrapper
55///
56/// This wrapper provides JavaScript-compatible bindings for KEM operations:
57/// - Integrates with the new modular architecture
58/// - Includes security validation
59/// - Provides consistent error handling
60/// - Supports all KEM algorithms
61#[cfg_attr(feature = "wasm", wasm_bindgen)]
62pub struct WasmKemContext {
63    inner: KemContext,
64    security_validator: SecurityValidator,
65}
66
67impl WasmKemContext {
68    /// Create a new WASM KEM context with default provider
69    pub fn new() -> WasmKemContext {
70        WasmKemContext {
71            inner: KemContext::with_default_provider(),
72            security_validator: SecurityValidator::new()
73                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
74        }
75    }
76
77    /// Create a new WASM KEM context with custom provider
78    pub fn with_provider(provider: &WasmCryptoProvider) -> WasmKemContext {
79        WasmKemContext {
80            inner: KemContext::with_provider(Box::new(provider.inner.clone())),
81            security_validator: SecurityValidator::new()
82                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
83        }
84    }
85}
86
87impl Default for WasmKemContext {
88    fn default() -> Self {
89        Self::new()
90    }
91}
92
93impl WasmKemContext {
94    /// Generate a keypair for the specified algorithm
95    ///
96    /// This method provides secure key generation with:
97    /// - Algorithm validation
98    /// - Security level verification
99    /// - Secure random generation
100    /// - Proper error handling
101    pub fn generate_keypair(
102        &mut self,
103        algorithm: &str,
104        randomness: Option<Uint8Array>,
105    ) -> Result<JsValue, JsValue> {
106        // Parse and validate algorithm
107        let algorithm = self
108            .parse_kem_algorithm(algorithm)
109            .map_err(error_to_js_value)?;
110
111        // Validate security level
112        convert_result(
113            self.security_validator
114                .validate_algorithm_category(algorithm, algorithm.category()),
115        )?;
116
117        // Convert randomness if provided
118        let randomness_vec = randomness.map(|rand| rand.to_vec());
119        let randomness_bytes = randomness_vec.as_deref();
120
121        // Generate keypair
122        let keypair = self
123            .inner
124            .generate_keypair(algorithm, randomness_bytes)
125            .map_err(error_to_js_value)?;
126
127        // Return as JavaScript object
128        #[cfg(feature = "wasm")]
129        {
130            let result = serde_json::json!({
131                "public_key": keypair.public_key.data,
132                "secret_key": keypair.secret_key.data,
133                "algorithm": algorithm.to_string(),
134                "security_level": 256 // Placeholder
135            });
136
137            serde_wasm_bindgen::to_value(&result)
138                .map_err(|e| JsValue::from_str(&format!("Serialization error: {:?}", e)))
139        }
140        #[cfg(not(feature = "wasm"))]
141        {
142            Err(JsValue::from_str("WASM feature not enabled"))
143        }
144    }
145
146    /// Encapsulate a shared secret using the given public key
147    ///
148    /// This method provides secure encapsulation with:
149    /// - Public key validation
150    /// - Algorithm verification
151    /// - Security level checking
152    /// - Proper error handling
153    pub fn encapsulate(
154        &self,
155        algorithm: &str,
156        public_key_data: &Uint8Array,
157        randomness: Option<Uint8Array>,
158    ) -> Result<JsValue, JsValue> {
159        // Parse and validate algorithm
160        let algorithm = self
161            .parse_kem_algorithm(algorithm)
162            .map_err(error_to_js_value)?;
163
164        // Validate public key size (simplified)
165        if public_key_data.length() == 0 {
166            return Err(JsValue::from_str("Invalid KEM public key: empty key"));
167        }
168
169        // Convert randomness if provided
170        let randomness_vec = randomness.map(|rand| rand.to_vec());
171        let randomness_bytes = randomness_vec.as_deref();
172
173        // Create public key using proper constructor
174        let public_key = crate::traits::KemPublicKey::new(public_key_data.to_vec());
175
176        // Encapsulate
177        let (ciphertext, shared_secret) = self
178            .inner
179            .encapsulate(algorithm, &public_key, randomness_bytes)
180            .map_err(error_to_js_value)?;
181
182        // Return as JavaScript object
183        #[cfg(feature = "wasm")]
184        {
185            let result = serde_json::json!({
186                "ciphertext": ciphertext,
187                "shared_secret": shared_secret,
188                "algorithm": algorithm.to_string(),
189                "security_level": 256 // Placeholder
190            });
191
192            serde_wasm_bindgen::to_value(&result)
193                .map_err(|e| JsValue::from_str(&format!("Serialization error: {:?}", e)))
194        }
195        #[cfg(not(feature = "wasm"))]
196        {
197            Err(JsValue::from_str("WASM feature not enabled"))
198        }
199    }
200
201    /// Decapsulate a shared secret using the given secret key and ciphertext
202    ///
203    /// This method provides secure decapsulation with:
204    /// - Secret key validation
205    /// - Ciphertext verification
206    /// - Algorithm checking
207    /// - Proper error handling
208    pub fn decapsulate(
209        &self,
210        algorithm: &str,
211        secret_key_data: &Uint8Array,
212        ciphertext: &Uint8Array,
213    ) -> Result<Vec<u8>, JsValue> {
214        // Parse and validate algorithm
215        let algorithm = self
216            .parse_kem_algorithm(algorithm)
217            .map_err(error_to_js_value)?;
218
219        // Validate algorithm category
220        self.security_validator
221            .validate_algorithm_category(algorithm, AlgorithmCategory::Kem)
222            .map_err(error_to_js_value)?;
223
224        // Validate secret key size
225        if secret_key_data.length() == 0 {
226            return Err(JsValue::from_str("Invalid KEM secret key: empty key"));
227        }
228
229        // Validate ciphertext size
230        if ciphertext.length() == 0 {
231            return Err(JsValue::from_str("Invalid message size: empty data"));
232        }
233
234        // Create secret key using proper constructor
235        let secret_key = crate::traits::KemSecretKey::new(secret_key_data.to_vec());
236
237        // Validate secret key
238        self.security_validator
239            .validate_secret_key(algorithm, secret_key.as_bytes())
240            .map_err(error_to_js_value)?;
241
242        // Validate ciphertext
243        self.security_validator
244            .validate_ciphertext(algorithm, &ciphertext.to_vec())
245            .map_err(error_to_js_value)?;
246
247        // Decapsulate
248        let shared_secret = self
249            .inner
250            .decapsulate(algorithm, &secret_key, &ciphertext.to_vec())
251            .map_err(error_to_js_value)?;
252
253        Ok(shared_secret)
254    }
255
256    /// Get the security level of the context
257    pub fn security_level(&self) -> u32 {
258        // Return the highest security level supported by the context
259        256 // This would be determined by the provider
260    }
261
262    /// Check if an algorithm is supported
263    pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
264        self.parse_kem_algorithm(algorithm).is_ok()
265    }
266
267    /// Get supported algorithms
268    pub fn supported_algorithms(&self) -> String {
269        #[allow(unused_mut)] // mut needed when feature flags are enabled
270        let mut algorithms = alloc::vec!["ml-kem-512", "ml-kem-768", "ml-kem-1024"];
271        #[cfg(feature = "wasm")]
272        {
273            serde_json::to_string(&algorithms).unwrap_or_else(|_| "[]".to_string())
274        }
275        #[cfg(not(feature = "wasm"))]
276        {
277            "[]".to_string()
278        }
279    }
280
281    /// Parse KEM algorithm from string
282    fn parse_kem_algorithm(&self, algorithm: &str) -> Result<Algorithm, crate::error::Error> {
283        parse_algorithm_wasm(algorithm).map_err(|_| crate::error::Error::InvalidAlgorithm {
284            algorithm: "Invalid algorithm name",
285        })
286    }
287}
288
289/// WASM-compatible Signature context wrapper
290///
291/// This wrapper provides JavaScript-compatible bindings for signature operations:
292/// - Integrates with the new modular architecture
293/// - Includes security validation
294/// - Provides consistent error handling
295/// - Supports all signature algorithms
296#[cfg_attr(feature = "wasm", wasm_bindgen)]
297pub struct WasmSignatureContext {
298    inner: SignatureContext,
299    security_validator: SecurityValidator,
300}
301
302impl WasmSignatureContext {
303    /// Create a new WASM Signature context with default provider
304    ///
305    /// Prefer [`Self::from_signature_context`] when building from the `lib-q` crate so that
306    /// real signature implementations (e.g. `lib-q-sig`) are wired in instead of the core stub.
307    pub fn new() -> WasmSignatureContext {
308        WasmSignatureContext {
309            inner: SignatureContext::with_default_provider(),
310            security_validator: SecurityValidator::new()
311                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
312        }
313    }
314
315    /// Wrap a Rust [`SignatureContext`] (for example one built with
316    /// `SignatureContext::with_provider(Box::new(lib_q_sig::LibQSignatureProvider::new()?))`).
317    pub fn from_signature_context(inner: SignatureContext) -> WasmSignatureContext {
318        WasmSignatureContext {
319            inner,
320            security_validator: SecurityValidator::new()
321                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
322        }
323    }
324}
325
326impl Default for WasmSignatureContext {
327    fn default() -> Self {
328        Self::new()
329    }
330}
331
332impl WasmSignatureContext {
333    /// Create a new WASM Signature context with custom provider
334    pub fn with_provider(provider: &WasmCryptoProvider) -> WasmSignatureContext {
335        WasmSignatureContext {
336            inner: SignatureContext::with_provider(Box::new(provider.inner.clone())),
337            security_validator: SecurityValidator::new()
338                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
339        }
340    }
341
342    /// Parse signature algorithm from string
343    fn parse_signature_algorithm(&self, algorithm: &str) -> Result<Algorithm, crate::error::Error> {
344        parse_algorithm_wasm(algorithm).map_err(|_| crate::error::Error::InvalidAlgorithm {
345            algorithm: "Invalid algorithm name",
346        })
347    }
348}
349
350#[cfg_attr(feature = "wasm", wasm_bindgen)]
351impl WasmSignatureContext {
352    /// Generate a keypair for the specified algorithm
353    pub fn generate_keypair(
354        &mut self,
355        algorithm: &str,
356        randomness: Option<Uint8Array>,
357    ) -> Result<JsValue, JsValue> {
358        // Parse and validate algorithm
359        let algorithm = self
360            .parse_signature_algorithm(algorithm)
361            .map_err(error_to_js_value)?;
362
363        // Validate security level
364        convert_result(
365            self.security_validator
366                .validate_algorithm_category(algorithm, algorithm.category()),
367        )?;
368
369        // Convert randomness if provided
370        let randomness_vec = randomness.map(|rand| rand.to_vec());
371        let randomness_bytes = randomness_vec.as_deref();
372
373        // Generate keypair
374        let keypair = self
375            .inner
376            .generate_keypair(algorithm, randomness_bytes)
377            .map_err(error_to_js_value)?;
378
379        // Return as JavaScript object
380        #[cfg(feature = "wasm")]
381        {
382            let result = serde_json::json!({
383                "public_key": keypair.public_key.data,
384                "secret_key": keypair.secret_key.data,
385                "algorithm": algorithm.to_string(),
386                "security_level": 256 // Placeholder
387            });
388
389            serde_wasm_bindgen::to_value(&result)
390                .map_err(|e| JsValue::from_str(&format!("Serialization error: {:?}", e)))
391        }
392        #[cfg(not(feature = "wasm"))]
393        {
394            Err(JsValue::from_str("WASM feature not enabled"))
395        }
396    }
397
398    /// Sign a message using the given secret key
399    pub fn sign(
400        &self,
401        algorithm: &str,
402        secret_key_data: &Uint8Array,
403        message: &Uint8Array,
404        randomness: Option<Uint8Array>,
405    ) -> Result<Vec<u8>, JsValue> {
406        // Parse and validate algorithm
407        let algorithm = self
408            .parse_signature_algorithm(algorithm)
409            .map_err(error_to_js_value)?;
410
411        // Validate secret key size (simplified)
412        if secret_key_data.length() == 0 {
413            return Err(JsValue::from_str("Invalid signature secret key: empty key"));
414        }
415
416        // Validate message size (simplified)
417        if message.length() == 0 {
418            return Err(JsValue::from_str("Invalid message size: empty data"));
419        }
420
421        // Convert randomness if provided
422        let randomness_vec = randomness.map(|rand| rand.to_vec());
423        let randomness_bytes = randomness_vec.as_deref();
424
425        // Create secret key using proper constructor
426        let secret_key = crate::traits::SigSecretKey::new(secret_key_data.to_vec());
427
428        // Sign
429        let signature = self
430            .inner
431            .sign(algorithm, &secret_key, &message.to_vec(), randomness_bytes)
432            .map_err(error_to_js_value)?;
433        Ok(signature)
434    }
435
436    /// Verify a signature using the given public key
437    pub fn verify(
438        &self,
439        algorithm: &str,
440        public_key_data: &Uint8Array,
441        message: &Uint8Array,
442        signature: &Uint8Array,
443    ) -> Result<bool, JsValue> {
444        // Parse and validate algorithm
445        let algorithm = self
446            .parse_signature_algorithm(algorithm)
447            .map_err(error_to_js_value)?;
448
449        // Validate public key size (simplified)
450        if public_key_data.length() == 0 {
451            return Err(JsValue::from_str("Invalid signature public key: empty key"));
452        }
453
454        // Validate message size (simplified)
455        if message.length() == 0 {
456            return Err(JsValue::from_str("Invalid message size: empty data"));
457        }
458
459        // Validate signature size (simplified)
460        if signature.length() == 0 {
461            return Err(JsValue::from_str("Invalid signature: empty data"));
462        }
463
464        // Create public key using proper constructor
465        let public_key = crate::traits::SigPublicKey::new(public_key_data.to_vec());
466
467        // Verify
468        let is_valid = self
469            .inner
470            .verify(
471                algorithm,
472                &public_key,
473                &message.to_vec(),
474                &signature.to_vec(),
475            )
476            .map_err(error_to_js_value)?;
477        Ok(is_valid)
478    }
479
480    /// Get the security level of the context
481    pub fn security_level(&self) -> u32 {
482        256 // This would be determined by the provider
483    }
484
485    /// Check if an algorithm is supported
486    pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
487        self.parse_signature_algorithm(algorithm).is_ok()
488    }
489
490    /// Get supported algorithms
491    pub fn supported_algorithms(&self) -> String {
492        #[cfg(feature = "wasm")]
493        {
494            serde_json::to_string(&WASM_SIGNATURE_ALGORITHM_IDS)
495                .unwrap_or_else(|_| "[]".to_string())
496        }
497        #[cfg(not(feature = "wasm"))]
498        {
499            "[]".to_string()
500        }
501    }
502}
503
504/// WASM-compatible Hash context wrapper
505///
506/// This wrapper provides JavaScript-compatible bindings for hash operations:
507/// - Integrates with the new modular architecture
508/// - Includes security validation
509/// - Provides consistent error handling
510/// - Supports all hash algorithms
511#[cfg_attr(feature = "wasm", wasm_bindgen)]
512pub struct WasmHashContext {
513    inner: HashContext,
514    security_validator: SecurityValidator,
515}
516
517impl WasmHashContext {
518    /// Create a new WASM Hash context with default provider
519    pub fn new() -> WasmHashContext {
520        WasmHashContext {
521            inner: HashContext::with_default_provider(),
522            security_validator: SecurityValidator::new()
523                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
524        }
525    }
526
527    /// Wrap a Rust [`HashContext`] that already has a hash-capable provider (for example from
528    /// `lib-q-hash::LibQHashProvider` in the umbrella crate).
529    pub fn from_hash_context(inner: HashContext) -> WasmHashContext {
530        WasmHashContext {
531            inner,
532            security_validator: SecurityValidator::new()
533                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
534        }
535    }
536}
537
538impl Default for WasmHashContext {
539    fn default() -> Self {
540        Self::new()
541    }
542}
543
544impl WasmHashContext {
545    /// Create a new WASM Hash context with custom provider
546    pub fn with_provider(provider: &WasmCryptoProvider) -> WasmHashContext {
547        WasmHashContext {
548            inner: HashContext::with_provider(Box::new(provider.inner.clone())),
549            security_validator: SecurityValidator::new()
550                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
551        }
552    }
553
554    /// Hash data using the specified algorithm
555    pub fn hash(&mut self, algorithm: &str, data: &Uint8Array) -> Result<JsValue, JsValue> {
556        // Parse and validate algorithm
557        let algorithm = self
558            .parse_hash_algorithm(algorithm)
559            .map_err(error_to_js_value)?;
560
561        // Validate algorithm category
562        self.security_validator
563            .validate_algorithm_category(algorithm, AlgorithmCategory::Hash)
564            .map_err(error_to_js_value)?;
565
566        // Validate data using security validator
567        self.security_validator
568            .validate_hash_input(&data.to_vec())
569            .map_err(error_to_js_value)?;
570
571        // Hash
572        let hash = self
573            .inner
574            .hash(algorithm, &data.to_vec())
575            .map_err(error_to_js_value)?;
576
577        // Return as JavaScript object
578        #[cfg(feature = "wasm")]
579        {
580            let result = serde_json::json!({
581                "hash": hash,
582                "algorithm": algorithm.to_string(),
583                "security_level": 256 // Placeholder
584            });
585
586            match serde_wasm_bindgen::to_value(&result) {
587                Ok(value) => Ok(value),
588                Err(e) => Err(JsValue::from_str(&format!("Serialization error: {:?}", e))),
589            }
590        }
591        #[cfg(not(feature = "wasm"))]
592        {
593            Err(JsValue::from_str("WASM feature not enabled"))
594        }
595    }
596
597    /// Get the security level of the context
598    pub fn security_level(&self) -> u32 {
599        256 // This would be determined by the provider
600    }
601
602    /// Check if an algorithm is supported
603    pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
604        self.parse_hash_algorithm(algorithm).is_ok()
605    }
606
607    /// Get supported algorithms
608    pub fn supported_algorithms(&self) -> String {
609        let algorithms = alloc::vec![
610            "sha3-224",
611            "sha3-256",
612            "sha3-384",
613            "sha3-512",
614            "shake128",
615            "shake256",
616            "sha-224",
617            "sha-256",
618            "sha-384",
619            "sha-512",
620            "sha-512/224",
621            "sha-512/256",
622            "cshake128",
623            "cshake256",
624            "keccak-224",
625            "keccak-256",
626            "keccak-384",
627            "keccak-512",
628            "kangarootwelve",
629            "turboshake128",
630            "turboshake256",
631            "kmac128",
632            "kmac256",
633            "tuplehash128",
634            "tuplehash256",
635            "parallelhash128",
636            "parallelhash256",
637        ];
638        #[cfg(feature = "wasm")]
639        {
640            serde_json::to_string(&algorithms).unwrap_or_else(|_| "[]".to_string())
641        }
642        #[cfg(not(feature = "wasm"))]
643        {
644            "[]".to_string()
645        }
646    }
647
648    /// Parse hash algorithm from string
649    fn parse_hash_algorithm(&self, algorithm: &str) -> Result<Algorithm, crate::error::Error> {
650        parse_algorithm_wasm(algorithm).map_err(|_| crate::error::Error::InvalidAlgorithm {
651            algorithm: "Invalid algorithm name",
652        })
653    }
654}
655
656/// WASM-compatible AEAD context wrapper
657///
658/// This wrapper provides JavaScript-compatible bindings for AEAD operations:
659/// - Integrates with the new modular architecture
660/// - Includes security validation
661/// - Provides consistent error handling
662/// - Supports all AEAD algorithms
663#[cfg_attr(feature = "wasm", wasm_bindgen)]
664pub struct WasmAeadContext {
665    inner: AeadContext,
666    security_validator: SecurityValidator,
667}
668
669impl WasmAeadContext {
670    /// Create a WASM AEAD context with **no** crypto provider configured.
671    ///
672    /// For AEAD backed by `lib-q-aead`, use the `lib-q` crate's `wasm::create_aead_context`, or
673    /// [`Self::from_aead_context`] / [`Self::with_provider`].
674    pub fn new() -> WasmAeadContext {
675        WasmAeadContext {
676            inner: AeadContext::new(),
677            security_validator: SecurityValidator::new()
678                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
679        }
680    }
681
682    /// Wrap a Rust [`AeadContext`] (for example one built with `AeadContext::with_aead_operations`).
683    pub fn from_aead_context(inner: AeadContext) -> WasmAeadContext {
684        WasmAeadContext {
685            inner,
686            security_validator: SecurityValidator::new()
687                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
688        }
689    }
690}
691
692impl Default for WasmAeadContext {
693    fn default() -> Self {
694        Self::new()
695    }
696}
697
698impl WasmAeadContext {
699    /// Create a new WASM AEAD context with custom provider
700    pub fn with_provider(provider: &WasmCryptoProvider) -> WasmAeadContext {
701        WasmAeadContext {
702            inner: AeadContext::with_provider(Box::new(provider.inner.clone())),
703            security_validator: SecurityValidator::new()
704                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
705        }
706    }
707
708    /// Encrypt data using the specified algorithm
709    pub fn encrypt(
710        &mut self,
711        algorithm: &str,
712        key: &Uint8Array,
713        nonce: &Uint8Array,
714        plaintext: &Uint8Array,
715        aad: Option<Uint8Array>,
716    ) -> Result<Vec<u8>, JsValue> {
717        // Parse and validate algorithm
718        let algorithm = self
719            .parse_aead_algorithm(algorithm)
720            .map_err(error_to_js_value)?;
721
722        // Validate algorithm category
723        self.security_validator
724            .validate_algorithm_category(algorithm, AlgorithmCategory::Aead)
725            .map_err(error_to_js_value)?;
726
727        // Validate key using security validator
728        self.security_validator
729            .validate_key_size(algorithm, &key.to_vec(), true)
730            .map_err(error_to_js_value)?;
731
732        // Validate nonce using security validator
733        self.security_validator
734            .validate_nonce(&nonce.to_vec())
735            .map_err(error_to_js_value)?;
736
737        // Validate plaintext using security validator
738        self.security_validator
739            .validate_aead_message(&plaintext.to_vec())
740            .map_err(error_to_js_value)?;
741
742        // Convert AAD if provided and validate
743        let aad_bytes = aad.map(|aad_data| aad_data.to_vec());
744        if let Some(ref aad_data) = aad_bytes {
745            self.security_validator
746                .validate_aead_message(aad_data)
747                .map_err(error_to_js_value)?;
748        }
749
750        // Encrypt
751        let aead_key = AeadKey::new(key.to_vec());
752        let nonce_obj = Nonce::new(nonce.to_vec());
753        let ciphertext = self
754            .inner
755            .encrypt(
756                algorithm,
757                &aead_key,
758                &nonce_obj,
759                &plaintext.to_vec(),
760                aad_bytes.as_deref(),
761            )
762            .map_err(error_to_js_value)?;
763        Ok(ciphertext)
764    }
765
766    /// Decrypt data using the specified algorithm.
767    ///
768    /// This WASM binding stays on **Layer A** ([`crate::traits::Aead`] / [`crate::api::AeadOperations`]):
769    /// only `Result`-style success versus error is exposed. Semantic decrypt
770    /// ([`crate::AeadDecryptSemantic`]) is not wired here to avoid silent ABI changes; use Rust
771    /// types directly when Layer B is required.
772    pub fn decrypt(
773        &self,
774        algorithm: &str,
775        key: &Uint8Array,
776        nonce: &Uint8Array,
777        ciphertext: &Uint8Array,
778        aad: Option<Uint8Array>,
779    ) -> Result<Vec<u8>, JsValue> {
780        // Parse and validate algorithm
781        let algorithm = self
782            .parse_aead_algorithm(algorithm)
783            .map_err(error_to_js_value)?;
784
785        // Validate algorithm category
786        self.security_validator
787            .validate_algorithm_category(algorithm, AlgorithmCategory::Aead)
788            .map_err(error_to_js_value)?;
789
790        // Validate key using security validator
791        self.security_validator
792            .validate_key_size(algorithm, &key.to_vec(), true)
793            .map_err(error_to_js_value)?;
794
795        // Validate nonce using security validator
796        self.security_validator
797            .validate_nonce(&nonce.to_vec())
798            .map_err(error_to_js_value)?;
799
800        // Validate ciphertext using security validator
801        self.security_validator
802            .validate_ciphertext(algorithm, &ciphertext.to_vec())
803            .map_err(error_to_js_value)?;
804
805        // Convert AAD if provided and validate
806        let aad_bytes = aad.map(|aad_data| aad_data.to_vec());
807        if let Some(ref aad_data) = aad_bytes {
808            self.security_validator
809                .validate_aead_message(aad_data)
810                .map_err(error_to_js_value)?;
811        }
812
813        // Decrypt
814        let aead_key = AeadKey::new(key.to_vec());
815        let nonce_obj = Nonce::new(nonce.to_vec());
816        let plaintext = self
817            .inner
818            .decrypt(
819                algorithm,
820                &aead_key,
821                &nonce_obj,
822                &ciphertext.to_vec(),
823                aad_bytes.as_deref(),
824            )
825            .map_err(error_to_js_value)?;
826        Ok(plaintext)
827    }
828
829    /// Get the security level of the context
830    pub fn security_level(&self) -> u32 {
831        256 // This would be determined by the provider
832    }
833
834    /// Check if an algorithm is supported
835    pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
836        self.parse_aead_algorithm(algorithm).is_ok()
837    }
838
839    /// Get supported algorithms
840    pub fn supported_algorithms(&self) -> String {
841        let algorithms = alloc::vec!["saturnin", "shake256-aead"];
842        #[cfg(feature = "wasm")]
843        {
844            serde_json::to_string(&algorithms).unwrap_or_else(|_| "[]".to_string())
845        }
846        #[cfg(not(feature = "wasm"))]
847        {
848            "[]".to_string()
849        }
850    }
851
852    /// Parse AEAD algorithm from string
853    fn parse_aead_algorithm(&self, algorithm: &str) -> Result<Algorithm, crate::error::Error> {
854        parse_algorithm_wasm(algorithm).map_err(|_| crate::error::Error::InvalidAlgorithm {
855            algorithm: "Invalid algorithm name",
856        })
857    }
858}
859
860/// WASM-compatible CryptoProvider wrapper
861///
862/// This wrapper provides JavaScript-compatible bindings for the crypto provider:
863/// - Integrates with the new modular architecture
864/// - Provides consistent error handling
865/// - Supports all cryptographic operations
866#[cfg_attr(feature = "wasm", wasm_bindgen)]
867pub struct WasmCryptoProvider {
868    inner: LibQCryptoProvider,
869}
870
871impl WasmCryptoProvider {
872    /// Create a new WASM CryptoProvider
873    pub fn new() -> WasmCryptoProvider {
874        WasmCryptoProvider {
875            inner: LibQCryptoProvider::new().unwrap_or_else(|_| LibQCryptoProvider::new().unwrap()),
876        }
877    }
878}
879
880impl Default for WasmCryptoProvider {
881    fn default() -> Self {
882        Self::new()
883    }
884}
885
886impl WasmCryptoProvider {
887    /// Get the provider information
888    pub fn info(&self) -> String {
889        #[cfg(feature = "wasm")]
890        {
891            serde_json::json!({
892                "name": "lib-Q Crypto Provider",
893                "version": crate::VERSION,
894                "features": {
895                    "kem": true,
896                    "signature": true,
897                    "hash": true,
898                    "aead": true,
899                    "security_hardened": true
900                }
901            })
902            .to_string()
903        }
904        #[cfg(not(feature = "wasm"))]
905        {
906            "{}".to_string()
907        }
908    }
909
910    /// Check if an algorithm is supported
911    pub fn is_algorithm_supported(&self, _algorithm: &str) -> bool {
912        // This would check against the actual provider implementation
913        true // Placeholder
914    }
915
916    /// Get supported algorithms by category
917    pub fn supported_algorithms(&self) -> String {
918        #[cfg(feature = "wasm")]
919        {
920            #[allow(unused_mut)] // mut needed when feature flags are enabled
921            let mut kem_algorithms = alloc::vec!["ml-kem-512", "ml-kem-768", "ml-kem-1024"];
922            let algorithms = serde_json::json!({
923                "kem": kem_algorithms,
924                "signature": WASM_SIGNATURE_ALGORITHM_IDS,
925                "hash": [
926                    "sha3-224", "sha3-256", "sha3-384", "sha3-512", "shake128", "shake256",
927                    "sha-224", "sha-256", "sha-384", "sha-512", "sha-512/224", "sha-512/256",
928                    "cshake128", "cshake256", "keccak-224", "keccak-256", "keccak-384", "keccak-512",
929                    "kangarootwelve", "turboshake128", "turboshake256", "kmac128", "kmac256",
930                    "tuplehash128", "tuplehash256", "parallelhash128", "parallelhash256",
931                ],
932                "aead": ["saturnin", "shake256-aead"]
933            });
934            algorithms.to_string()
935        }
936        #[cfg(not(feature = "wasm"))]
937        {
938            "{}".to_string()
939        }
940    }
941}
942
943#[cfg(test)]
944mod tests {
945    use super::*;
946
947    #[test]
948    fn test_wasm_kem_context_creation() {
949        let context = WasmKemContext::new();
950        assert_eq!(context.security_level(), 256);
951    }
952
953    #[test]
954    fn test_wasm_signature_context_creation() {
955        let context = WasmSignatureContext::new();
956        assert_eq!(context.security_level(), 256);
957    }
958
959    #[test]
960    fn test_wasm_hash_context_creation() {
961        let context = WasmHashContext::new();
962        assert_eq!(context.security_level(), 256);
963    }
964
965    #[test]
966    fn test_wasm_aead_context_creation() {
967        let context = WasmAeadContext::new();
968        assert_eq!(context.security_level(), 256);
969    }
970
971    #[test]
972    fn test_wasm_crypto_provider_creation() {
973        let provider = WasmCryptoProvider::new();
974        let info = provider.info();
975        assert!(info.contains("lib-Q") || info == "{}");
976    }
977
978    #[test]
979    #[cfg(target_arch = "wasm32")]
980    fn test_wasm_kem_context_operations() {
981        let mut context = WasmKemContext::new();
982
983        // Test that operations return proper NotImplemented errors
984        let result = context.generate_keypair("ml-kem-512", None);
985        assert!(result.is_err());
986        if let Err(error) = result {
987            let error_str = error.as_string().unwrap_or_default();
988            assert!(error_str.contains("NotImplemented") || error_str.contains("WASM"));
989        }
990    }
991
992    #[test]
993    #[cfg(target_arch = "wasm32")]
994    fn test_wasm_signature_context_operations() {
995        let mut context = WasmSignatureContext::new();
996
997        // Test that operations return proper NotImplemented errors
998        let result = context.generate_keypair("ml-dsa-65", None);
999        assert!(result.is_err());
1000        if let Err(error) = result {
1001            let error_str = error.as_string().unwrap_or_default();
1002            assert!(error_str.contains("NotImplemented") || error_str.contains("WASM"));
1003        }
1004    }
1005
1006    #[test]
1007    #[cfg(target_arch = "wasm32")]
1008    fn test_wasm_hash_context_operations() {
1009        let mut context = WasmHashContext::new();
1010
1011        // Test that operations return proper NotImplemented errors
1012        let data = Uint8Array::new_with_length(10);
1013        let result = context.hash("sha3-256", &data);
1014        assert!(result.is_err());
1015        if let Err(error) = result {
1016            let error_str = error.as_string().unwrap_or_default();
1017            assert!(error_str.contains("NotImplemented") || error_str.contains("WASM"));
1018        }
1019    }
1020
1021    #[test]
1022    #[cfg(target_arch = "wasm32")]
1023    fn test_wasm_aead_context_operations() {
1024        let mut context = WasmAeadContext::new();
1025
1026        // Test that operations return proper NotImplemented errors
1027        let key = Uint8Array::new_with_length(32);
1028        let nonce = Uint8Array::new_with_length(16);
1029        let plaintext = Uint8Array::new_with_length(10);
1030
1031        let result = context.encrypt("saturnin", &key, &nonce, &plaintext, None);
1032        assert!(result.is_err());
1033        if let Err(error) = result {
1034            let error_str = error.as_string().unwrap_or_default();
1035            assert!(
1036                error_str.contains("Provider not configured") ||
1037                    error_str.contains("NotImplemented") ||
1038                    error_str.contains("WASM")
1039            );
1040        }
1041    }
1042}