1#[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};
38use crate::providers::LibQCryptoProvider;
40use crate::security::SecurityValidator;
41use crate::traits::{
42 AeadKey,
43 Nonce,
44};
45use crate::wasm::conversions::WASM_SIGNATURE_ALGORITHM_IDS;
47use crate::wasm::error::{
48 convert_result,
49 error_to_js_value,
50 parse_algorithm_wasm,
51 };
53
54#[cfg_attr(feature = "wasm", wasm_bindgen)]
62pub struct WasmKemContext {
63 inner: KemContext,
64 security_validator: SecurityValidator,
65}
66
67impl WasmKemContext {
68 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 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 pub fn generate_keypair(
102 &mut self,
103 algorithm: &str,
104 randomness: Option<Uint8Array>,
105 ) -> Result<JsValue, JsValue> {
106 let algorithm = self
108 .parse_kem_algorithm(algorithm)
109 .map_err(error_to_js_value)?;
110
111 convert_result(
113 self.security_validator
114 .validate_algorithm_category(algorithm, algorithm.category()),
115 )?;
116
117 let randomness_vec = randomness.map(|rand| rand.to_vec());
119 let randomness_bytes = randomness_vec.as_deref();
120
121 let keypair = self
123 .inner
124 .generate_keypair(algorithm, randomness_bytes)
125 .map_err(error_to_js_value)?;
126
127 #[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 });
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 pub fn encapsulate(
154 &self,
155 algorithm: &str,
156 public_key_data: &Uint8Array,
157 randomness: Option<Uint8Array>,
158 ) -> Result<JsValue, JsValue> {
159 let algorithm = self
161 .parse_kem_algorithm(algorithm)
162 .map_err(error_to_js_value)?;
163
164 if public_key_data.length() == 0 {
166 return Err(JsValue::from_str("Invalid KEM public key: empty key"));
167 }
168
169 let randomness_vec = randomness.map(|rand| rand.to_vec());
171 let randomness_bytes = randomness_vec.as_deref();
172
173 let public_key = crate::traits::KemPublicKey::new(public_key_data.to_vec());
175
176 let (ciphertext, shared_secret) = self
178 .inner
179 .encapsulate(algorithm, &public_key, randomness_bytes)
180 .map_err(error_to_js_value)?;
181
182 #[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 });
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 pub fn decapsulate(
209 &self,
210 algorithm: &str,
211 secret_key_data: &Uint8Array,
212 ciphertext: &Uint8Array,
213 ) -> Result<Vec<u8>, JsValue> {
214 let algorithm = self
216 .parse_kem_algorithm(algorithm)
217 .map_err(error_to_js_value)?;
218
219 self.security_validator
221 .validate_algorithm_category(algorithm, AlgorithmCategory::Kem)
222 .map_err(error_to_js_value)?;
223
224 if secret_key_data.length() == 0 {
226 return Err(JsValue::from_str("Invalid KEM secret key: empty key"));
227 }
228
229 if ciphertext.length() == 0 {
231 return Err(JsValue::from_str("Invalid message size: empty data"));
232 }
233
234 let secret_key = crate::traits::KemSecretKey::new(secret_key_data.to_vec());
236
237 self.security_validator
239 .validate_secret_key(algorithm, secret_key.as_bytes())
240 .map_err(error_to_js_value)?;
241
242 self.security_validator
244 .validate_ciphertext(algorithm, &ciphertext.to_vec())
245 .map_err(error_to_js_value)?;
246
247 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 pub fn security_level(&self) -> u32 {
258 256 }
261
262 pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
264 self.parse_kem_algorithm(algorithm).is_ok()
265 }
266
267 pub fn supported_algorithms(&self) -> String {
269 #[allow(unused_mut)] 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 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#[cfg_attr(feature = "wasm", wasm_bindgen)]
297pub struct WasmSignatureContext {
298 inner: SignatureContext,
299 security_validator: SecurityValidator,
300}
301
302impl WasmSignatureContext {
303 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 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 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 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 pub fn generate_keypair(
354 &mut self,
355 algorithm: &str,
356 randomness: Option<Uint8Array>,
357 ) -> Result<JsValue, JsValue> {
358 let algorithm = self
360 .parse_signature_algorithm(algorithm)
361 .map_err(error_to_js_value)?;
362
363 convert_result(
365 self.security_validator
366 .validate_algorithm_category(algorithm, algorithm.category()),
367 )?;
368
369 let randomness_vec = randomness.map(|rand| rand.to_vec());
371 let randomness_bytes = randomness_vec.as_deref();
372
373 let keypair = self
375 .inner
376 .generate_keypair(algorithm, randomness_bytes)
377 .map_err(error_to_js_value)?;
378
379 #[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 });
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 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 let algorithm = self
408 .parse_signature_algorithm(algorithm)
409 .map_err(error_to_js_value)?;
410
411 if secret_key_data.length() == 0 {
413 return Err(JsValue::from_str("Invalid signature secret key: empty key"));
414 }
415
416 if message.length() == 0 {
418 return Err(JsValue::from_str("Invalid message size: empty data"));
419 }
420
421 let randomness_vec = randomness.map(|rand| rand.to_vec());
423 let randomness_bytes = randomness_vec.as_deref();
424
425 let secret_key = crate::traits::SigSecretKey::new(secret_key_data.to_vec());
427
428 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 pub fn verify(
438 &self,
439 algorithm: &str,
440 public_key_data: &Uint8Array,
441 message: &Uint8Array,
442 signature: &Uint8Array,
443 ) -> Result<bool, JsValue> {
444 let algorithm = self
446 .parse_signature_algorithm(algorithm)
447 .map_err(error_to_js_value)?;
448
449 if public_key_data.length() == 0 {
451 return Err(JsValue::from_str("Invalid signature public key: empty key"));
452 }
453
454 if message.length() == 0 {
456 return Err(JsValue::from_str("Invalid message size: empty data"));
457 }
458
459 if signature.length() == 0 {
461 return Err(JsValue::from_str("Invalid signature: empty data"));
462 }
463
464 let public_key = crate::traits::SigPublicKey::new(public_key_data.to_vec());
466
467 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 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 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 pub fn security_level(&self) -> u32 {
567 256 }
569
570 pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
572 self.parse_signature_algorithm(algorithm).is_ok()
573 }
574
575 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#[cfg_attr(feature = "wasm", wasm_bindgen)]
597pub struct WasmHashContext {
598 inner: HashContext,
599 security_validator: SecurityValidator,
600}
601
602impl WasmHashContext {
603 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 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 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 pub fn hash(&mut self, algorithm: &str, data: &Uint8Array) -> Result<JsValue, JsValue> {
641 let algorithm = self
643 .parse_hash_algorithm(algorithm)
644 .map_err(error_to_js_value)?;
645
646 self.security_validator
648 .validate_algorithm_category(algorithm, AlgorithmCategory::Hash)
649 .map_err(error_to_js_value)?;
650
651 self.security_validator
653 .validate_hash_input(&data.to_vec())
654 .map_err(error_to_js_value)?;
655
656 let hash = self
658 .inner
659 .hash(algorithm, &data.to_vec())
660 .map_err(error_to_js_value)?;
661
662 #[cfg(feature = "wasm")]
664 {
665 let result = serde_json::json!({
666 "hash": hash,
667 "algorithm": algorithm.to_string(),
668 "security_level": 256 });
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 pub fn security_level(&self) -> u32 {
684 256 }
686
687 pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
689 self.parse_hash_algorithm(algorithm).is_ok()
690 }
691
692 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 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#[cfg_attr(feature = "wasm", wasm_bindgen)]
749pub struct WasmAeadContext {
750 inner: AeadContext,
751 security_validator: SecurityValidator,
752}
753
754impl WasmAeadContext {
755 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 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 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 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 let algorithm = self
804 .parse_aead_algorithm(algorithm)
805 .map_err(error_to_js_value)?;
806
807 self.security_validator
809 .validate_algorithm_category(algorithm, AlgorithmCategory::Aead)
810 .map_err(error_to_js_value)?;
811
812 self.security_validator
814 .validate_key_size(algorithm, &key.to_vec(), true)
815 .map_err(error_to_js_value)?;
816
817 self.security_validator
819 .validate_nonce(&nonce.to_vec())
820 .map_err(error_to_js_value)?;
821
822 self.security_validator
824 .validate_aead_message(&plaintext.to_vec())
825 .map_err(error_to_js_value)?;
826
827 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 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 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 let algorithm = self
867 .parse_aead_algorithm(algorithm)
868 .map_err(error_to_js_value)?;
869
870 self.security_validator
872 .validate_algorithm_category(algorithm, AlgorithmCategory::Aead)
873 .map_err(error_to_js_value)?;
874
875 self.security_validator
877 .validate_key_size(algorithm, &key.to_vec(), true)
878 .map_err(error_to_js_value)?;
879
880 self.security_validator
882 .validate_nonce(&nonce.to_vec())
883 .map_err(error_to_js_value)?;
884
885 self.security_validator
887 .validate_ciphertext(algorithm, &ciphertext.to_vec())
888 .map_err(error_to_js_value)?;
889
890 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 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 pub fn security_level(&self) -> u32 {
916 256 }
918
919 pub fn is_algorithm_supported(&self, algorithm: &str) -> bool {
921 self.parse_aead_algorithm(algorithm).is_ok()
922 }
923
924 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 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#[cfg_attr(feature = "wasm", wasm_bindgen)]
952pub struct WasmCryptoProvider {
953 inner: LibQCryptoProvider,
954}
955
956impl WasmCryptoProvider {
957 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 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 pub fn is_algorithm_supported(&self, _algorithm: &str) -> bool {
997 true }
1000
1001 pub fn supported_algorithms(&self) -> String {
1003 #[cfg(feature = "wasm")]
1004 {
1005 #[allow(unused_mut)] 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 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 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 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 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}