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    /// Sign a message under a signing context (FIPS-204 / FIPS-205 domain separation)
481    ///
482    /// The resulting signature verifies only under the same `context` bytes — see
483    /// [`Self::verify_with_context`]. An empty `context` matches [`Self::sign`].
484    pub fn sign_with_context(
485        &self,
486        algorithm: &str,
487        secret_key_data: &Uint8Array,
488        message: &Uint8Array,
489        context: &Uint8Array,
490        randomness: Option<Uint8Array>,
491    ) -> Result<Vec<u8>, JsValue> {
492        let algorithm = self
493            .parse_signature_algorithm(algorithm)
494            .map_err(error_to_js_value)?;
495
496        if secret_key_data.length() == 0 {
497            return Err(JsValue::from_str("Invalid signature secret key: empty key"));
498        }
499
500        if message.length() == 0 {
501            return Err(JsValue::from_str("Invalid message size: empty data"));
502        }
503
504        let randomness_vec = randomness.map(|rand| rand.to_vec());
505        let randomness_bytes = randomness_vec.as_deref();
506
507        let secret_key = crate::traits::SigSecretKey::new(secret_key_data.to_vec());
508
509        let signature = self
510            .inner
511            .sign_with_context(
512                algorithm,
513                &secret_key,
514                &message.to_vec(),
515                &context.to_vec(),
516                randomness_bytes,
517            )
518            .map_err(error_to_js_value)?;
519        Ok(signature)
520    }
521
522    /// Verify a signature under a signing context (FIPS-204 / FIPS-205 domain separation)
523    ///
524    /// Returns `false` unless `context` matches the context the signature was produced under.
525    /// An empty `context` matches [`Self::verify`].
526    pub fn verify_with_context(
527        &self,
528        algorithm: &str,
529        public_key_data: &Uint8Array,
530        message: &Uint8Array,
531        context: &Uint8Array,
532        signature: &Uint8Array,
533    ) -> Result<bool, JsValue> {
534        let algorithm = self
535            .parse_signature_algorithm(algorithm)
536            .map_err(error_to_js_value)?;
537
538        if public_key_data.length() == 0 {
539            return Err(JsValue::from_str("Invalid signature public key: empty key"));
540        }
541
542        if message.length() == 0 {
543            return Err(JsValue::from_str("Invalid message size: empty data"));
544        }
545
546        if signature.length() == 0 {
547            return Err(JsValue::from_str("Invalid signature: empty data"));
548        }
549
550        let public_key = crate::traits::SigPublicKey::new(public_key_data.to_vec());
551
552        let is_valid = self
553            .inner
554            .verify_with_context(
555                algorithm,
556                &public_key,
557                &message.to_vec(),
558                &context.to_vec(),
559                &signature.to_vec(),
560            )
561            .map_err(error_to_js_value)?;
562        Ok(is_valid)
563    }
564
565    /// Get the security level of the context
566    pub fn security_level(&self) -> u32 {
567        256 // This would be determined by the provider
568    }
569
570    /// Check if an algorithm is supported
571    pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
572        self.parse_signature_algorithm(algorithm).is_ok()
573    }
574
575    /// Get supported algorithms
576    pub fn supported_algorithms(&self) -> String {
577        #[cfg(feature = "wasm")]
578        {
579            serde_json::to_string(&WASM_SIGNATURE_ALGORITHM_IDS)
580                .unwrap_or_else(|_| "[]".to_string())
581        }
582        #[cfg(not(feature = "wasm"))]
583        {
584            "[]".to_string()
585        }
586    }
587}
588
589/// WASM-compatible Hash context wrapper
590///
591/// This wrapper provides JavaScript-compatible bindings for hash operations:
592/// - Integrates with the new modular architecture
593/// - Includes security validation
594/// - Provides consistent error handling
595/// - Supports all hash algorithms
596#[cfg_attr(feature = "wasm", wasm_bindgen)]
597pub struct WasmHashContext {
598    inner: HashContext,
599    security_validator: SecurityValidator,
600}
601
602impl WasmHashContext {
603    /// Create a new WASM Hash context with default provider
604    pub fn new() -> WasmHashContext {
605        WasmHashContext {
606            inner: HashContext::with_default_provider(),
607            security_validator: SecurityValidator::new()
608                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
609        }
610    }
611
612    /// Wrap a Rust [`HashContext`] that already has a hash-capable provider (for example from
613    /// `lib-q-hash::LibQHashProvider` in the umbrella crate).
614    pub fn from_hash_context(inner: HashContext) -> WasmHashContext {
615        WasmHashContext {
616            inner,
617            security_validator: SecurityValidator::new()
618                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
619        }
620    }
621}
622
623impl Default for WasmHashContext {
624    fn default() -> Self {
625        Self::new()
626    }
627}
628
629impl WasmHashContext {
630    /// Create a new WASM Hash context with custom provider
631    pub fn with_provider(provider: &WasmCryptoProvider) -> WasmHashContext {
632        WasmHashContext {
633            inner: HashContext::with_provider(Box::new(provider.inner.clone())),
634            security_validator: SecurityValidator::new()
635                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
636        }
637    }
638
639    /// Hash data using the specified algorithm
640    pub fn hash(&mut self, algorithm: &str, data: &Uint8Array) -> Result<JsValue, JsValue> {
641        // Parse and validate algorithm
642        let algorithm = self
643            .parse_hash_algorithm(algorithm)
644            .map_err(error_to_js_value)?;
645
646        // Validate algorithm category
647        self.security_validator
648            .validate_algorithm_category(algorithm, AlgorithmCategory::Hash)
649            .map_err(error_to_js_value)?;
650
651        // Validate data using security validator
652        self.security_validator
653            .validate_hash_input(&data.to_vec())
654            .map_err(error_to_js_value)?;
655
656        // Hash
657        let hash = self
658            .inner
659            .hash(algorithm, &data.to_vec())
660            .map_err(error_to_js_value)?;
661
662        // Return as JavaScript object
663        #[cfg(feature = "wasm")]
664        {
665            let result = serde_json::json!({
666                "hash": hash,
667                "algorithm": algorithm.to_string(),
668                "security_level": 256 // Placeholder
669            });
670
671            match serde_wasm_bindgen::to_value(&result) {
672                Ok(value) => Ok(value),
673                Err(e) => Err(JsValue::from_str(&format!("Serialization error: {:?}", e))),
674            }
675        }
676        #[cfg(not(feature = "wasm"))]
677        {
678            Err(JsValue::from_str("WASM feature not enabled"))
679        }
680    }
681
682    /// Get the security level of the context
683    pub fn security_level(&self) -> u32 {
684        256 // This would be determined by the provider
685    }
686
687    /// Check if an algorithm is supported
688    pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
689        self.parse_hash_algorithm(algorithm).is_ok()
690    }
691
692    /// Get supported algorithms
693    pub fn supported_algorithms(&self) -> String {
694        let algorithms = alloc::vec![
695            "sha3-224",
696            "sha3-256",
697            "sha3-384",
698            "sha3-512",
699            "shake128",
700            "shake256",
701            "sha-224",
702            "sha-256",
703            "sha-384",
704            "sha-512",
705            "sha-512/224",
706            "sha-512/256",
707            "cshake128",
708            "cshake256",
709            "keccak-224",
710            "keccak-256",
711            "keccak-384",
712            "keccak-512",
713            "kangarootwelve",
714            "turboshake128",
715            "turboshake256",
716            "kmac128",
717            "kmac256",
718            "tuplehash128",
719            "tuplehash256",
720            "parallelhash128",
721            "parallelhash256",
722        ];
723        #[cfg(feature = "wasm")]
724        {
725            serde_json::to_string(&algorithms).unwrap_or_else(|_| "[]".to_string())
726        }
727        #[cfg(not(feature = "wasm"))]
728        {
729            "[]".to_string()
730        }
731    }
732
733    /// Parse hash algorithm from string
734    fn parse_hash_algorithm(&self, algorithm: &str) -> Result<Algorithm, crate::error::Error> {
735        parse_algorithm_wasm(algorithm).map_err(|_| crate::error::Error::InvalidAlgorithm {
736            algorithm: "Invalid algorithm name",
737        })
738    }
739}
740
741/// WASM-compatible AEAD context wrapper
742///
743/// This wrapper provides JavaScript-compatible bindings for AEAD operations:
744/// - Integrates with the new modular architecture
745/// - Includes security validation
746/// - Provides consistent error handling
747/// - Supports all AEAD algorithms
748#[cfg_attr(feature = "wasm", wasm_bindgen)]
749pub struct WasmAeadContext {
750    inner: AeadContext,
751    security_validator: SecurityValidator,
752}
753
754impl WasmAeadContext {
755    /// Create a WASM AEAD context with **no** crypto provider configured.
756    ///
757    /// For AEAD backed by `lib-q-aead`, use the `lib-q` crate's `wasm::create_aead_context`, or
758    /// [`Self::from_aead_context`] / [`Self::with_provider`].
759    pub fn new() -> WasmAeadContext {
760        WasmAeadContext {
761            inner: AeadContext::new(),
762            security_validator: SecurityValidator::new()
763                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
764        }
765    }
766
767    /// Wrap a Rust [`AeadContext`] (for example one built with `AeadContext::with_aead_operations`).
768    pub fn from_aead_context(inner: AeadContext) -> WasmAeadContext {
769        WasmAeadContext {
770            inner,
771            security_validator: SecurityValidator::new()
772                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
773        }
774    }
775}
776
777impl Default for WasmAeadContext {
778    fn default() -> Self {
779        Self::new()
780    }
781}
782
783impl WasmAeadContext {
784    /// Create a new WASM AEAD context with custom provider
785    pub fn with_provider(provider: &WasmCryptoProvider) -> WasmAeadContext {
786        WasmAeadContext {
787            inner: AeadContext::with_provider(Box::new(provider.inner.clone())),
788            security_validator: SecurityValidator::new()
789                .unwrap_or_else(|_| SecurityValidator::new().unwrap()),
790        }
791    }
792
793    /// Encrypt data using the specified algorithm
794    pub fn encrypt(
795        &mut self,
796        algorithm: &str,
797        key: &Uint8Array,
798        nonce: &Uint8Array,
799        plaintext: &Uint8Array,
800        aad: Option<Uint8Array>,
801    ) -> Result<Vec<u8>, JsValue> {
802        // Parse and validate algorithm
803        let algorithm = self
804            .parse_aead_algorithm(algorithm)
805            .map_err(error_to_js_value)?;
806
807        // Validate algorithm category
808        self.security_validator
809            .validate_algorithm_category(algorithm, AlgorithmCategory::Aead)
810            .map_err(error_to_js_value)?;
811
812        // Validate key using security validator
813        self.security_validator
814            .validate_key_size(algorithm, &key.to_vec(), true)
815            .map_err(error_to_js_value)?;
816
817        // Validate nonce using security validator
818        self.security_validator
819            .validate_nonce(&nonce.to_vec())
820            .map_err(error_to_js_value)?;
821
822        // Validate plaintext using security validator
823        self.security_validator
824            .validate_aead_message(&plaintext.to_vec())
825            .map_err(error_to_js_value)?;
826
827        // Convert AAD if provided and validate
828        let aad_bytes = aad.map(|aad_data| aad_data.to_vec());
829        if let Some(ref aad_data) = aad_bytes {
830            self.security_validator
831                .validate_aead_message(aad_data)
832                .map_err(error_to_js_value)?;
833        }
834
835        // Encrypt
836        let aead_key = AeadKey::new(key.to_vec());
837        let nonce_obj = Nonce::new(nonce.to_vec());
838        let ciphertext = self
839            .inner
840            .encrypt(
841                algorithm,
842                &aead_key,
843                &nonce_obj,
844                &plaintext.to_vec(),
845                aad_bytes.as_deref(),
846            )
847            .map_err(error_to_js_value)?;
848        Ok(ciphertext)
849    }
850
851    /// Decrypt data using the specified algorithm.
852    ///
853    /// This WASM binding stays on **Layer A** ([`crate::traits::Aead`] / [`crate::api::AeadOperations`]):
854    /// only `Result`-style success versus error is exposed. Semantic decrypt
855    /// ([`crate::AeadDecryptSemantic`]) is not wired here to avoid silent ABI changes; use Rust
856    /// types directly when Layer B is required.
857    pub fn decrypt(
858        &self,
859        algorithm: &str,
860        key: &Uint8Array,
861        nonce: &Uint8Array,
862        ciphertext: &Uint8Array,
863        aad: Option<Uint8Array>,
864    ) -> Result<Vec<u8>, JsValue> {
865        // Parse and validate algorithm
866        let algorithm = self
867            .parse_aead_algorithm(algorithm)
868            .map_err(error_to_js_value)?;
869
870        // Validate algorithm category
871        self.security_validator
872            .validate_algorithm_category(algorithm, AlgorithmCategory::Aead)
873            .map_err(error_to_js_value)?;
874
875        // Validate key using security validator
876        self.security_validator
877            .validate_key_size(algorithm, &key.to_vec(), true)
878            .map_err(error_to_js_value)?;
879
880        // Validate nonce using security validator
881        self.security_validator
882            .validate_nonce(&nonce.to_vec())
883            .map_err(error_to_js_value)?;
884
885        // Validate ciphertext using security validator
886        self.security_validator
887            .validate_ciphertext(algorithm, &ciphertext.to_vec())
888            .map_err(error_to_js_value)?;
889
890        // Convert AAD if provided and validate
891        let aad_bytes = aad.map(|aad_data| aad_data.to_vec());
892        if let Some(ref aad_data) = aad_bytes {
893            self.security_validator
894                .validate_aead_message(aad_data)
895                .map_err(error_to_js_value)?;
896        }
897
898        // Decrypt
899        let aead_key = AeadKey::new(key.to_vec());
900        let nonce_obj = Nonce::new(nonce.to_vec());
901        let plaintext = self
902            .inner
903            .decrypt(
904                algorithm,
905                &aead_key,
906                &nonce_obj,
907                &ciphertext.to_vec(),
908                aad_bytes.as_deref(),
909            )
910            .map_err(error_to_js_value)?;
911        Ok(plaintext)
912    }
913
914    /// Get the security level of the context
915    pub fn security_level(&self) -> u32 {
916        256 // This would be determined by the provider
917    }
918
919    /// Check if an algorithm is supported
920    pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
921        self.parse_aead_algorithm(algorithm).is_ok()
922    }
923
924    /// Get supported algorithms
925    pub fn supported_algorithms(&self) -> String {
926        let algorithms = alloc::vec!["saturnin", "shake256-aead"];
927        #[cfg(feature = "wasm")]
928        {
929            serde_json::to_string(&algorithms).unwrap_or_else(|_| "[]".to_string())
930        }
931        #[cfg(not(feature = "wasm"))]
932        {
933            "[]".to_string()
934        }
935    }
936
937    /// Parse AEAD algorithm from string
938    fn parse_aead_algorithm(&self, algorithm: &str) -> Result<Algorithm, crate::error::Error> {
939        parse_algorithm_wasm(algorithm).map_err(|_| crate::error::Error::InvalidAlgorithm {
940            algorithm: "Invalid algorithm name",
941        })
942    }
943}
944
945/// WASM-compatible CryptoProvider wrapper
946///
947/// This wrapper provides JavaScript-compatible bindings for the crypto provider:
948/// - Integrates with the new modular architecture
949/// - Provides consistent error handling
950/// - Supports all cryptographic operations
951#[cfg_attr(feature = "wasm", wasm_bindgen)]
952pub struct WasmCryptoProvider {
953    inner: LibQCryptoProvider,
954}
955
956impl WasmCryptoProvider {
957    /// Create a new WASM CryptoProvider
958    pub fn new() -> WasmCryptoProvider {
959        WasmCryptoProvider {
960            inner: LibQCryptoProvider::new().unwrap_or_else(|_| LibQCryptoProvider::new().unwrap()),
961        }
962    }
963}
964
965impl Default for WasmCryptoProvider {
966    fn default() -> Self {
967        Self::new()
968    }
969}
970
971impl WasmCryptoProvider {
972    /// Get the provider information
973    pub fn info(&self) -> String {
974        #[cfg(feature = "wasm")]
975        {
976            serde_json::json!({
977                "name": "lib-Q Crypto Provider",
978                "version": crate::VERSION,
979                "features": {
980                    "kem": true,
981                    "signature": true,
982                    "hash": true,
983                    "aead": true,
984                    "security_hardened": true
985                }
986            })
987            .to_string()
988        }
989        #[cfg(not(feature = "wasm"))]
990        {
991            "{}".to_string()
992        }
993    }
994
995    /// Check if an algorithm is supported
996    pub fn is_algorithm_supported(&self, _algorithm: &str) -> bool {
997        // This would check against the actual provider implementation
998        true // Placeholder
999    }
1000
1001    /// Get supported algorithms by category
1002    pub fn supported_algorithms(&self) -> String {
1003        #[cfg(feature = "wasm")]
1004        {
1005            #[allow(unused_mut)] // mut needed when feature flags are enabled
1006            let mut kem_algorithms = alloc::vec!["ml-kem-512", "ml-kem-768", "ml-kem-1024"];
1007            let algorithms = serde_json::json!({
1008                "kem": kem_algorithms,
1009                "signature": WASM_SIGNATURE_ALGORITHM_IDS,
1010                "hash": [
1011                    "sha3-224", "sha3-256", "sha3-384", "sha3-512", "shake128", "shake256",
1012                    "sha-224", "sha-256", "sha-384", "sha-512", "sha-512/224", "sha-512/256",
1013                    "cshake128", "cshake256", "keccak-224", "keccak-256", "keccak-384", "keccak-512",
1014                    "kangarootwelve", "turboshake128", "turboshake256", "kmac128", "kmac256",
1015                    "tuplehash128", "tuplehash256", "parallelhash128", "parallelhash256",
1016                ],
1017                "aead": ["saturnin", "shake256-aead"]
1018            });
1019            algorithms.to_string()
1020        }
1021        #[cfg(not(feature = "wasm"))]
1022        {
1023            "{}".to_string()
1024        }
1025    }
1026}
1027
1028#[cfg(test)]
1029mod tests {
1030    use super::*;
1031
1032    #[test]
1033    fn test_wasm_kem_context_creation() {
1034        let context = WasmKemContext::new();
1035        assert_eq!(context.security_level(), 256);
1036    }
1037
1038    #[test]
1039    fn test_wasm_signature_context_creation() {
1040        let context = WasmSignatureContext::new();
1041        assert_eq!(context.security_level(), 256);
1042    }
1043
1044    #[test]
1045    fn test_wasm_hash_context_creation() {
1046        let context = WasmHashContext::new();
1047        assert_eq!(context.security_level(), 256);
1048    }
1049
1050    #[test]
1051    fn test_wasm_aead_context_creation() {
1052        let context = WasmAeadContext::new();
1053        assert_eq!(context.security_level(), 256);
1054    }
1055
1056    #[test]
1057    fn test_wasm_crypto_provider_creation() {
1058        let provider = WasmCryptoProvider::new();
1059        let info = provider.info();
1060        assert!(info.contains("lib-Q") || info == "{}");
1061    }
1062
1063    #[test]
1064    #[cfg(target_arch = "wasm32")]
1065    fn test_wasm_kem_context_operations() {
1066        let mut context = WasmKemContext::new();
1067
1068        // Test that operations return proper NotImplemented errors
1069        let result = context.generate_keypair("ml-kem-512", None);
1070        assert!(result.is_err());
1071        if let Err(error) = result {
1072            let error_str = error.as_string().unwrap_or_default();
1073            assert!(error_str.contains("NotImplemented") || error_str.contains("WASM"));
1074        }
1075    }
1076
1077    #[test]
1078    #[cfg(target_arch = "wasm32")]
1079    fn test_wasm_signature_context_operations() {
1080        let mut context = WasmSignatureContext::new();
1081
1082        // Test that operations return proper NotImplemented errors
1083        let result = context.generate_keypair("ml-dsa-65", None);
1084        assert!(result.is_err());
1085        if let Err(error) = result {
1086            let error_str = error.as_string().unwrap_or_default();
1087            assert!(error_str.contains("NotImplemented") || error_str.contains("WASM"));
1088        }
1089    }
1090
1091    #[test]
1092    #[cfg(target_arch = "wasm32")]
1093    fn test_wasm_hash_context_operations() {
1094        let mut context = WasmHashContext::new();
1095
1096        // Test that operations return proper NotImplemented errors
1097        let data = Uint8Array::new_with_length(10);
1098        let result = context.hash("sha3-256", &data);
1099        assert!(result.is_err());
1100        if let Err(error) = result {
1101            let error_str = error.as_string().unwrap_or_default();
1102            assert!(error_str.contains("NotImplemented") || error_str.contains("WASM"));
1103        }
1104    }
1105
1106    #[test]
1107    #[cfg(target_arch = "wasm32")]
1108    fn test_wasm_aead_context_operations() {
1109        let mut context = WasmAeadContext::new();
1110
1111        // Test that operations return proper NotImplemented errors
1112        let key = Uint8Array::new_with_length(32);
1113        let nonce = Uint8Array::new_with_length(16);
1114        let plaintext = Uint8Array::new_with_length(10);
1115
1116        let result = context.encrypt("saturnin", &key, &nonce, &plaintext, None);
1117        assert!(result.is_err());
1118        if let Err(error) = result {
1119            let error_str = error.as_string().unwrap_or_default();
1120            assert!(
1121                error_str.contains("Provider not configured") ||
1122                    error_str.contains("NotImplemented") ||
1123                    error_str.contains("WASM")
1124            );
1125        }
1126    }
1127}