1use crate::seqstring::global_string;
32use crate::stack::{Stack, pop, push};
33use crate::value::Value;
34
35use aes_gcm::{
36 Aes256Gcm, Nonce,
37 aead::{Aead, KeyInit as AesKeyInit, OsRng, rand_core::RngCore as AeadRngCore},
38};
39use base64::{Engine, engine::general_purpose::STANDARD};
40use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
41use hmac::{Hmac, Mac};
42use rand::thread_rng;
43use sha2::{Digest, Sha256};
44use subtle::ConstantTimeEq;
45use uuid::Uuid;
46
47const AES_NONCE_SIZE: usize = 12;
48const AES_KEY_SIZE: usize = 32;
49const AES_GCM_TAG_SIZE: usize = 16;
50const MIN_PBKDF2_ITERATIONS: i64 = 1_000;
51
52type HmacSha256 = Hmac<Sha256>;
53
54#[unsafe(no_mangle)]
63pub unsafe extern "C" fn patch_seq_sha256(stack: Stack) -> Stack {
64 assert!(!stack.is_null(), "sha256: stack is empty");
65
66 let (stack, value) = unsafe { pop(stack) };
67
68 match value {
69 Value::String(s) => {
70 let mut hasher = Sha256::new();
71 hasher.update(s.as_str().as_bytes());
72 let result = hasher.finalize();
73 let hex_digest = hex::encode(result);
74 unsafe { push(stack, Value::String(global_string(hex_digest))) }
75 }
76 _ => panic!("sha256: expected String on stack, got {:?}", value),
77 }
78}
79
80#[unsafe(no_mangle)]
90pub unsafe extern "C" fn patch_seq_hmac_sha256(stack: Stack) -> Stack {
91 assert!(!stack.is_null(), "hmac-sha256: stack is empty");
92
93 let (stack, key_value) = unsafe { pop(stack) };
94 let (stack, msg_value) = unsafe { pop(stack) };
95
96 match (msg_value, key_value) {
97 (Value::String(msg), Value::String(key)) => {
98 let mut mac = <HmacSha256 as Mac>::new_from_slice(key.as_str().as_bytes())
99 .expect("HMAC can take any key");
100 mac.update(msg.as_str().as_bytes());
101 let result = mac.finalize();
102 let hex_sig = hex::encode(result.into_bytes());
103 unsafe { push(stack, Value::String(global_string(hex_sig))) }
104 }
105 (msg, key) => panic!(
106 "hmac-sha256: expected (String, String) on stack, got ({:?}, {:?})",
107 msg, key
108 ),
109 }
110}
111
112#[unsafe(no_mangle)]
126pub unsafe extern "C" fn patch_seq_constant_time_eq(stack: Stack) -> Stack {
127 assert!(!stack.is_null(), "constant-time-eq: stack is empty");
128
129 let (stack, b_value) = unsafe { pop(stack) };
130 let (stack, a_value) = unsafe { pop(stack) };
131
132 match (a_value, b_value) {
133 (Value::String(a), Value::String(b)) => {
134 let a_bytes = a.as_str().as_bytes();
135 let b_bytes = b.as_str().as_bytes();
136
137 let eq = a_bytes.ct_eq(b_bytes);
140
141 unsafe { push(stack, Value::Bool(bool::from(eq))) }
142 }
143 (a, b) => panic!(
144 "constant-time-eq: expected (String, String) on stack, got ({:?}, {:?})",
145 a, b
146 ),
147 }
148}
149
150#[unsafe(no_mangle)]
164pub unsafe extern "C" fn patch_seq_random_bytes(stack: Stack) -> Stack {
165 assert!(!stack.is_null(), "random-bytes: stack is empty");
166
167 let (stack, value) = unsafe { pop(stack) };
168
169 match value {
170 Value::Int(n) => {
171 if n < 0 {
172 panic!("random-bytes: byte count must be non-negative, got {}", n);
173 }
174 if n > 1024 {
175 panic!("random-bytes: byte count too large (max 1024), got {}", n);
176 }
177
178 let mut bytes = vec![0u8; n as usize];
179 thread_rng().fill_bytes(&mut bytes);
180 let hex_str = hex::encode(&bytes);
181 unsafe { push(stack, Value::String(global_string(hex_str))) }
182 }
183 _ => panic!("random-bytes: expected Int on stack, got {:?}", value),
184 }
185}
186
187#[unsafe(no_mangle)]
196pub unsafe extern "C" fn patch_seq_uuid4(stack: Stack) -> Stack {
197 assert!(!stack.is_null(), "uuid4: stack is empty");
198
199 let uuid = Uuid::new_v4();
200 unsafe { push(stack, Value::String(global_string(uuid.to_string()))) }
201}
202
203#[unsafe(no_mangle)]
217pub unsafe extern "C" fn patch_seq_random_int(stack: Stack) -> Stack {
218 assert!(!stack.is_null(), "random-int: stack is empty");
219
220 let (stack, max_val) = unsafe { pop(stack) };
221 let (stack, min_val) = unsafe { pop(stack) };
222
223 match (min_val, max_val) {
224 (Value::Int(min), Value::Int(max)) => {
225 let result = if min >= max {
226 min } else {
228 random_int_range(min, max)
229 };
230 unsafe { push(stack, Value::Int(result)) }
231 }
232 (min, max) => panic!(
233 "random-int: expected (Int, Int) on stack, got ({:?}, {:?})",
234 min, max
235 ),
236 }
237}
238
239fn random_int_range(min: i64, max: i64) -> i64 {
243 let range = (max as u64).wrapping_sub(min as u64);
246 if range == 0 {
247 return min;
248 }
249
250 let threshold = u64::MAX - (u64::MAX % range);
255
256 loop {
257 let mut bytes = [0u8; 8];
259 thread_rng().fill_bytes(&mut bytes);
260 let val = u64::from_le_bytes(bytes);
261
262 if val < threshold {
263 let result = (min as u64).wrapping_add(val % range);
266 return result as i64;
267 }
268 }
270}
271
272#[unsafe(no_mangle)]
287pub unsafe extern "C" fn patch_seq_crypto_aes_gcm_encrypt(stack: Stack) -> Stack {
288 assert!(!stack.is_null(), "crypto.aes-gcm-encrypt: stack is null");
289
290 let (stack, key_val) = unsafe { pop(stack) };
291 let (stack, plaintext_val) = unsafe { pop(stack) };
292
293 match (plaintext_val, key_val) {
294 (Value::String(plaintext), Value::String(key_hex)) => {
295 match aes_gcm_encrypt(plaintext.as_str(), key_hex.as_str()) {
296 Some(ciphertext) => {
297 let stack = unsafe { push(stack, Value::String(global_string(ciphertext))) };
298 unsafe { push(stack, Value::Bool(true)) }
299 }
300 None => {
301 let stack = unsafe { push(stack, Value::String(global_string(String::new()))) };
302 unsafe { push(stack, Value::Bool(false)) }
303 }
304 }
305 }
306 _ => panic!("crypto.aes-gcm-encrypt: expected two Strings on stack"),
307 }
308}
309
310#[unsafe(no_mangle)]
325pub unsafe extern "C" fn patch_seq_crypto_aes_gcm_decrypt(stack: Stack) -> Stack {
326 assert!(!stack.is_null(), "crypto.aes-gcm-decrypt: stack is null");
327
328 let (stack, key_val) = unsafe { pop(stack) };
329 let (stack, ciphertext_val) = unsafe { pop(stack) };
330
331 match (ciphertext_val, key_val) {
332 (Value::String(ciphertext), Value::String(key_hex)) => {
333 match aes_gcm_decrypt(ciphertext.as_str(), key_hex.as_str()) {
334 Some(plaintext) => {
335 let stack = unsafe { push(stack, Value::String(global_string(plaintext))) };
336 unsafe { push(stack, Value::Bool(true)) }
337 }
338 None => {
339 let stack = unsafe { push(stack, Value::String(global_string(String::new()))) };
340 unsafe { push(stack, Value::Bool(false)) }
341 }
342 }
343 }
344 _ => panic!("crypto.aes-gcm-decrypt: expected two Strings on stack"),
345 }
346}
347
348#[unsafe(no_mangle)]
364pub unsafe extern "C" fn patch_seq_crypto_pbkdf2_sha256(stack: Stack) -> Stack {
365 assert!(!stack.is_null(), "crypto.pbkdf2-sha256: stack is null");
366
367 let (stack, iterations_val) = unsafe { pop(stack) };
368 let (stack, salt_val) = unsafe { pop(stack) };
369 let (stack, password_val) = unsafe { pop(stack) };
370
371 match (password_val, salt_val, iterations_val) {
372 (Value::String(password), Value::String(salt), Value::Int(iterations)) => {
373 if iterations < MIN_PBKDF2_ITERATIONS {
375 let stack = unsafe { push(stack, Value::String(global_string(String::new()))) };
376 return unsafe { push(stack, Value::Bool(false)) };
377 }
378
379 let key = derive_key_pbkdf2(password.as_str(), salt.as_str(), iterations as u32);
380 let key_hex = hex::encode(key);
381 let stack = unsafe { push(stack, Value::String(global_string(key_hex))) };
382 unsafe { push(stack, Value::Bool(true)) }
383 }
384 _ => panic!("crypto.pbkdf2-sha256: expected String, String, Int on stack"),
385 }
386}
387
388fn aes_gcm_encrypt(plaintext: &str, key_hex: &str) -> Option<String> {
391 let key_bytes = hex::decode(key_hex).ok()?;
393 if key_bytes.len() != AES_KEY_SIZE {
394 return None;
395 }
396
397 let cipher = Aes256Gcm::new_from_slice(&key_bytes).ok()?;
399
400 let mut nonce_bytes = [0u8; AES_NONCE_SIZE];
402 OsRng.fill_bytes(&mut nonce_bytes);
403 let nonce = Nonce::from_slice(&nonce_bytes);
404
405 let ciphertext = cipher.encrypt(nonce, plaintext.as_bytes()).ok()?;
407
408 let mut combined = Vec::with_capacity(AES_NONCE_SIZE + ciphertext.len());
410 combined.extend_from_slice(&nonce_bytes);
411 combined.extend_from_slice(&ciphertext);
412
413 Some(STANDARD.encode(&combined))
414}
415
416fn aes_gcm_decrypt(ciphertext_b64: &str, key_hex: &str) -> Option<String> {
417 let combined = STANDARD.decode(ciphertext_b64).ok()?;
419 if combined.len() < AES_NONCE_SIZE + AES_GCM_TAG_SIZE {
420 return None;
422 }
423
424 let key_bytes = hex::decode(key_hex).ok()?;
426 if key_bytes.len() != AES_KEY_SIZE {
427 return None;
428 }
429
430 let (nonce_bytes, ciphertext) = combined.split_at(AES_NONCE_SIZE);
432 let nonce = Nonce::from_slice(nonce_bytes);
433
434 let cipher = Aes256Gcm::new_from_slice(&key_bytes).ok()?;
436 let plaintext_bytes = cipher.decrypt(nonce, ciphertext).ok()?;
437
438 String::from_utf8(plaintext_bytes).ok()
439}
440
441fn derive_key_pbkdf2(password: &str, salt: &str, iterations: u32) -> [u8; AES_KEY_SIZE] {
442 let mut key = [0u8; AES_KEY_SIZE];
443 pbkdf2::pbkdf2_hmac::<Sha256>(password.as_bytes(), salt.as_bytes(), iterations, &mut key);
444 key
445}
446
447#[unsafe(no_mangle)]
462pub unsafe extern "C" fn patch_seq_crypto_ed25519_keypair(stack: Stack) -> Stack {
463 assert!(!stack.is_null(), "crypto.ed25519-keypair: stack is null");
464
465 let signing_key = SigningKey::generate(&mut OsRng);
466 let verifying_key = signing_key.verifying_key();
467
468 let private_hex = hex::encode(signing_key.to_bytes());
469 let public_hex = hex::encode(verifying_key.to_bytes());
470
471 let stack = unsafe { push(stack, Value::String(global_string(public_hex))) };
472 unsafe { push(stack, Value::String(global_string(private_hex))) }
473}
474
475#[unsafe(no_mangle)]
490pub unsafe extern "C" fn patch_seq_crypto_ed25519_sign(stack: Stack) -> Stack {
491 assert!(!stack.is_null(), "crypto.ed25519-sign: stack is null");
492
493 let (stack, key_val) = unsafe { pop(stack) };
494 let (stack, msg_val) = unsafe { pop(stack) };
495
496 match (msg_val, key_val) {
497 (Value::String(message), Value::String(private_key_hex)) => {
498 match ed25519_sign(message.as_str(), private_key_hex.as_str()) {
499 Some(signature) => {
500 let stack = unsafe { push(stack, Value::String(global_string(signature))) };
501 unsafe { push(stack, Value::Bool(true)) }
502 }
503 None => {
504 let stack = unsafe { push(stack, Value::String(global_string(String::new()))) };
505 unsafe { push(stack, Value::Bool(false)) }
506 }
507 }
508 }
509 _ => panic!("crypto.ed25519-sign: expected String, String on stack"),
510 }
511}
512
513#[unsafe(no_mangle)]
528pub unsafe extern "C" fn patch_seq_crypto_ed25519_verify(stack: Stack) -> Stack {
529 assert!(!stack.is_null(), "crypto.ed25519-verify: stack is null");
530
531 let (stack, pubkey_val) = unsafe { pop(stack) };
532 let (stack, sig_val) = unsafe { pop(stack) };
533 let (stack, msg_val) = unsafe { pop(stack) };
534
535 match (msg_val, sig_val, pubkey_val) {
536 (Value::String(message), Value::String(signature_hex), Value::String(public_key_hex)) => {
537 let valid = ed25519_verify(
538 message.as_str(),
539 signature_hex.as_str(),
540 public_key_hex.as_str(),
541 );
542 unsafe { push(stack, Value::Bool(valid)) }
543 }
544 _ => panic!("crypto.ed25519-verify: expected String, String, String on stack"),
545 }
546}
547
548fn ed25519_sign(message: &str, private_key_hex: &str) -> Option<String> {
551 let key_bytes = hex::decode(private_key_hex).ok()?;
552 if key_bytes.len() != 32 {
553 return None;
554 }
555
556 let key_array: [u8; 32] = key_bytes.try_into().ok()?;
557 let signing_key = SigningKey::from_bytes(&key_array);
558 let signature = signing_key.sign(message.as_bytes());
559
560 Some(hex::encode(signature.to_bytes()))
561}
562
563fn ed25519_verify(message: &str, signature_hex: &str, public_key_hex: &str) -> bool {
564 let verify_inner = || -> Option<bool> {
565 let sig_bytes = hex::decode(signature_hex).ok()?;
566 if sig_bytes.len() != 64 {
567 return Some(false);
568 }
569
570 let pubkey_bytes = hex::decode(public_key_hex).ok()?;
571 if pubkey_bytes.len() != 32 {
572 return Some(false);
573 }
574
575 let sig_array: [u8; 64] = sig_bytes.try_into().ok()?;
576 let pubkey_array: [u8; 32] = pubkey_bytes.try_into().ok()?;
577
578 let signature = Signature::from_bytes(&sig_array);
579 let verifying_key = VerifyingKey::from_bytes(&pubkey_array).ok()?;
580
581 Some(verifying_key.verify(message.as_bytes(), &signature).is_ok())
582 };
583
584 verify_inner().unwrap_or(false)
585}
586
587#[cfg(test)]
588mod tests {
589 use super::*;
590 use crate::stack::pop;
591
592 #[test]
593 fn test_sha256() {
594 unsafe {
595 let stack = crate::stack::alloc_test_stack();
596 let stack = push(stack, Value::String(global_string("hello".to_string())));
597 let stack = patch_seq_sha256(stack);
598 let (_, value) = pop(stack);
599
600 match value {
601 Value::String(s) => {
602 assert_eq!(
604 s.as_str(),
605 "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
606 );
607 }
608 _ => panic!("Expected String"),
609 }
610 }
611 }
612
613 #[test]
614 fn test_sha256_empty() {
615 unsafe {
616 let stack = crate::stack::alloc_test_stack();
617 let stack = push(stack, Value::String(global_string(String::new())));
618 let stack = patch_seq_sha256(stack);
619 let (_, value) = pop(stack);
620
621 match value {
622 Value::String(s) => {
623 assert_eq!(
625 s.as_str(),
626 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
627 );
628 }
629 _ => panic!("Expected String"),
630 }
631 }
632 }
633
634 #[test]
635 fn test_hmac_sha256() {
636 unsafe {
637 let stack = crate::stack::alloc_test_stack();
638 let stack = push(stack, Value::String(global_string("message".to_string())));
639 let stack = push(stack, Value::String(global_string("secret".to_string())));
640 let stack = patch_seq_hmac_sha256(stack);
641 let (_, value) = pop(stack);
642
643 match value {
644 Value::String(s) => {
645 assert_eq!(
647 s.as_str(),
648 "8b5f48702995c1598c573db1e21866a9b825d4a794d169d7060a03605796360b"
649 );
650 }
651 _ => panic!("Expected String"),
652 }
653 }
654 }
655
656 #[test]
657 fn test_constant_time_eq_equal() {
658 unsafe {
659 let stack = crate::stack::alloc_test_stack();
660 let stack = push(stack, Value::String(global_string("hello".to_string())));
661 let stack = push(stack, Value::String(global_string("hello".to_string())));
662 let stack = patch_seq_constant_time_eq(stack);
663 let (_, value) = pop(stack);
664
665 match value {
666 Value::Bool(b) => assert!(b),
667 _ => panic!("Expected Bool"),
668 }
669 }
670 }
671
672 #[test]
673 fn test_constant_time_eq_different() {
674 unsafe {
675 let stack = crate::stack::alloc_test_stack();
676 let stack = push(stack, Value::String(global_string("hello".to_string())));
677 let stack = push(stack, Value::String(global_string("world".to_string())));
678 let stack = patch_seq_constant_time_eq(stack);
679 let (_, value) = pop(stack);
680
681 match value {
682 Value::Bool(b) => assert!(!b),
683 _ => panic!("Expected Bool"),
684 }
685 }
686 }
687
688 #[test]
689 fn test_constant_time_eq_different_lengths() {
690 unsafe {
691 let stack = crate::stack::alloc_test_stack();
692 let stack = push(stack, Value::String(global_string("hello".to_string())));
693 let stack = push(stack, Value::String(global_string("hi".to_string())));
694 let stack = patch_seq_constant_time_eq(stack);
695 let (_, value) = pop(stack);
696
697 match value {
698 Value::Bool(b) => assert!(!b),
699 _ => panic!("Expected Bool"),
700 }
701 }
702 }
703
704 #[test]
705 fn test_random_bytes() {
706 unsafe {
707 let stack = crate::stack::alloc_test_stack();
708 let stack = push(stack, Value::Int(16));
709 let stack = patch_seq_random_bytes(stack);
710 let (_, value) = pop(stack);
711
712 match value {
713 Value::String(s) => {
714 assert_eq!(s.as_str().len(), 32);
716 assert!(hex::decode(s.as_str()).is_ok());
718 }
719 _ => panic!("Expected String"),
720 }
721 }
722 }
723
724 #[test]
725 fn test_random_bytes_zero() {
726 unsafe {
727 let stack = crate::stack::alloc_test_stack();
728 let stack = push(stack, Value::Int(0));
729 let stack = patch_seq_random_bytes(stack);
730 let (_, value) = pop(stack);
731
732 match value {
733 Value::String(s) => {
734 assert_eq!(s.as_str(), "");
735 }
736 _ => panic!("Expected String"),
737 }
738 }
739 }
740
741 #[test]
742 fn test_uuid4() {
743 unsafe {
744 let stack = crate::stack::alloc_test_stack();
745 let stack = patch_seq_uuid4(stack);
746 let (_, value) = pop(stack);
747
748 match value {
749 Value::String(s) => {
750 assert_eq!(s.as_str().len(), 36);
752 assert_eq!(s.as_str().chars().filter(|c| *c == '-').count(), 4);
753 assert_eq!(s.as_str().chars().nth(14), Some('4'));
755 }
756 _ => panic!("Expected String"),
757 }
758 }
759 }
760
761 #[test]
762 fn test_uuid4_unique() {
763 unsafe {
764 let stack = crate::stack::alloc_test_stack();
765 let stack = patch_seq_uuid4(stack);
766 let (stack, value1) = pop(stack);
767 let stack = patch_seq_uuid4(stack);
768 let (_, value2) = pop(stack);
769
770 match (value1, value2) {
771 (Value::String(s1), Value::String(s2)) => {
772 assert_ne!(s1.as_str(), s2.as_str());
773 }
774 _ => panic!("Expected Strings"),
775 }
776 }
777 }
778
779 #[test]
780 fn test_random_bytes_max_limit() {
781 unsafe {
782 let stack = crate::stack::alloc_test_stack();
783 let stack = push(stack, Value::Int(1024)); let stack = patch_seq_random_bytes(stack);
785 let (_, value) = pop(stack);
786
787 match value {
788 Value::String(s) => {
789 assert_eq!(s.as_str().len(), 2048);
791 }
792 _ => panic!("Expected String"),
793 }
794 }
795 }
796 #[test]
802 fn test_aes_gcm_roundtrip() {
803 unsafe {
804 let stack = crate::stack::alloc_test_stack();
805
806 let key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
808
809 let stack = push(
810 stack,
811 Value::String(global_string("hello world".to_string())),
812 );
813 let stack = push(stack, Value::String(global_string(key_hex.to_string())));
814
815 let stack = patch_seq_crypto_aes_gcm_encrypt(stack);
817
818 let (stack, success) = pop(stack);
820 assert_eq!(success, Value::Bool(true));
821
822 let stack = push(stack, Value::String(global_string(key_hex.to_string())));
824
825 let stack = patch_seq_crypto_aes_gcm_decrypt(stack);
827
828 let (stack, success) = pop(stack);
830 assert_eq!(success, Value::Bool(true));
831
832 let (_, result) = pop(stack);
834 if let Value::String(s) = result {
835 assert_eq!(s.as_str(), "hello world");
836 } else {
837 panic!("expected string");
838 }
839 }
840 }
841
842 #[test]
843 fn test_aes_gcm_wrong_key() {
844 unsafe {
845 let stack = crate::stack::alloc_test_stack();
846
847 let key1 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
848 let key2 = "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210";
849
850 let stack = push(
851 stack,
852 Value::String(global_string("secret message".to_string())),
853 );
854 let stack = push(stack, Value::String(global_string(key1.to_string())));
855
856 let stack = patch_seq_crypto_aes_gcm_encrypt(stack);
858 let (stack, success) = pop(stack);
859 assert_eq!(success, Value::Bool(true));
860
861 let stack = push(stack, Value::String(global_string(key2.to_string())));
863 let stack = patch_seq_crypto_aes_gcm_decrypt(stack);
864
865 let (_, success) = pop(stack);
867 assert_eq!(success, Value::Bool(false));
868 }
869 }
870
871 #[test]
872 fn test_aes_gcm_invalid_key_length() {
873 unsafe {
874 let stack = crate::stack::alloc_test_stack();
875
876 let short_key = "0123456789abcdef";
878
879 let stack = push(stack, Value::String(global_string("test data".to_string())));
880 let stack = push(stack, Value::String(global_string(short_key.to_string())));
881
882 let stack = patch_seq_crypto_aes_gcm_encrypt(stack);
883 let (_, success) = pop(stack);
884 assert_eq!(success, Value::Bool(false));
885 }
886 }
887
888 #[test]
889 fn test_aes_gcm_invalid_ciphertext() {
890 unsafe {
891 let stack = crate::stack::alloc_test_stack();
892
893 let key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
894
895 let stack = push(
897 stack,
898 Value::String(global_string("not-valid-base64!!!".to_string())),
899 );
900 let stack = push(stack, Value::String(global_string(key.to_string())));
901
902 let stack = patch_seq_crypto_aes_gcm_decrypt(stack);
903 let (_, success) = pop(stack);
904 assert_eq!(success, Value::Bool(false));
905 }
906 }
907
908 #[test]
909 fn test_aes_gcm_empty_plaintext() {
910 let key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
911
912 let ciphertext = aes_gcm_encrypt("", key).unwrap();
913 let decrypted = aes_gcm_decrypt(&ciphertext, key).unwrap();
914 assert_eq!(decrypted, "");
915 }
916
917 #[test]
918 fn test_aes_gcm_special_characters() {
919 let key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
920 let plaintext = "Hello\nWorld\tTab\"Quote\\Backslash";
921
922 let ciphertext = aes_gcm_encrypt(plaintext, key).unwrap();
923 let decrypted = aes_gcm_decrypt(&ciphertext, key).unwrap();
924 assert_eq!(decrypted, plaintext);
925 }
926
927 #[test]
930 fn test_pbkdf2_sha256() {
931 unsafe {
932 let stack = crate::stack::alloc_test_stack();
933
934 let stack = push(
935 stack,
936 Value::String(global_string("my-password".to_string())),
937 );
938 let stack = push(
939 stack,
940 Value::String(global_string("random-salt".to_string())),
941 );
942 let stack = push(stack, Value::Int(10000));
943
944 let stack = patch_seq_crypto_pbkdf2_sha256(stack);
945
946 let (stack, success) = pop(stack);
948 assert_eq!(success, Value::Bool(true));
949
950 let (_, result) = pop(stack);
952 if let Value::String(s) = result {
953 assert_eq!(s.as_str().len(), 64);
954 assert!(hex::decode(s.as_str()).is_ok());
956 } else {
957 panic!("expected string");
958 }
959 }
960 }
961
962 #[test]
963 fn test_pbkdf2_deterministic() {
964 let key1 = derive_key_pbkdf2("password", "salt", 10000);
966 let key2 = derive_key_pbkdf2("password", "salt", 10000);
967 assert_eq!(key1, key2);
968
969 let key3 = derive_key_pbkdf2("password", "different-salt", 10000);
971 assert_ne!(key1, key3);
972 }
973
974 #[test]
975 fn test_pbkdf2_invalid_iterations() {
976 unsafe {
977 let stack = crate::stack::alloc_test_stack();
978
979 let stack = push(stack, Value::String(global_string("password".to_string())));
980 let stack = push(stack, Value::String(global_string("salt".to_string())));
981 let stack = push(stack, Value::Int(0)); let stack = patch_seq_crypto_pbkdf2_sha256(stack);
984
985 let (_, success) = pop(stack);
986 assert_eq!(success, Value::Bool(false));
987 }
988 }
989
990 #[test]
991 fn test_encrypt_decrypt_with_derived_key() {
992 let password = "user-secret-password";
994 let salt = "unique-user-salt";
995 let iterations = 10000u32;
996
997 let key = derive_key_pbkdf2(password, salt, iterations);
999 let key_hex = hex::encode(key);
1000
1001 let plaintext = "sensitive data to protect";
1003 let ciphertext = aes_gcm_encrypt(plaintext, &key_hex).unwrap();
1004
1005 let decrypted = aes_gcm_decrypt(&ciphertext, &key_hex).unwrap();
1007 assert_eq!(decrypted, plaintext);
1008 }
1009
1010 #[test]
1013 fn test_ed25519_sign_verify() {
1014 let message = "Hello, World!";
1015
1016 let signing_key = SigningKey::generate(&mut OsRng);
1018 let verifying_key = signing_key.verifying_key();
1019
1020 let private_hex = hex::encode(signing_key.to_bytes());
1021 let public_hex = hex::encode(verifying_key.to_bytes());
1022
1023 let signature = ed25519_sign(message, &private_hex).unwrap();
1025 assert_eq!(signature.len(), 128); assert!(ed25519_verify(message, &signature, &public_hex));
1029 }
1030
1031 #[test]
1032 fn test_ed25519_wrong_message() {
1033 let message = "Original message";
1034 let wrong_message = "Wrong message";
1035
1036 let signing_key = SigningKey::generate(&mut OsRng);
1037 let verifying_key = signing_key.verifying_key();
1038
1039 let private_hex = hex::encode(signing_key.to_bytes());
1040 let public_hex = hex::encode(verifying_key.to_bytes());
1041
1042 let signature = ed25519_sign(message, &private_hex).unwrap();
1043
1044 assert!(!ed25519_verify(wrong_message, &signature, &public_hex));
1046 }
1047
1048 #[test]
1049 fn test_ed25519_wrong_key() {
1050 let message = "Test message";
1051
1052 let signing_key1 = SigningKey::generate(&mut OsRng);
1053 let signing_key2 = SigningKey::generate(&mut OsRng);
1054
1055 let private_hex = hex::encode(signing_key1.to_bytes());
1056 let wrong_public_hex = hex::encode(signing_key2.verifying_key().to_bytes());
1057
1058 let signature = ed25519_sign(message, &private_hex).unwrap();
1059
1060 assert!(!ed25519_verify(message, &signature, &wrong_public_hex));
1062 }
1063
1064 #[test]
1065 fn test_ed25519_invalid_key_length() {
1066 let message = "Test message";
1067 let invalid_key = "tooshort";
1068
1069 assert!(ed25519_sign(message, invalid_key).is_none());
1071 }
1072
1073 #[test]
1074 fn test_ed25519_invalid_signature() {
1075 let message = "Test message";
1076
1077 let signing_key = SigningKey::generate(&mut OsRng);
1078 let public_hex = hex::encode(signing_key.verifying_key().to_bytes());
1079
1080 let invalid_signature = "0".repeat(128); assert!(!ed25519_verify(message, &invalid_signature, &public_hex));
1084 }
1085
1086 #[test]
1087 fn test_ed25519_empty_message() {
1088 let message = "";
1089
1090 let signing_key = SigningKey::generate(&mut OsRng);
1091 let verifying_key = signing_key.verifying_key();
1092
1093 let private_hex = hex::encode(signing_key.to_bytes());
1094 let public_hex = hex::encode(verifying_key.to_bytes());
1095
1096 let signature = ed25519_sign(message, &private_hex).unwrap();
1098
1099 assert!(ed25519_verify(message, &signature, &public_hex));
1101 }
1102
1103 #[test]
1104 fn test_ed25519_keypair_ffi() {
1105 unsafe {
1106 let stack = crate::stack::alloc_test_stack();
1107
1108 let stack = patch_seq_crypto_ed25519_keypair(stack);
1109
1110 let (stack, private_key) = pop(stack);
1111 let (_, public_key) = pop(stack);
1112
1113 if let Value::String(pk) = public_key {
1115 assert_eq!(pk.as_str().len(), 64);
1116 } else {
1117 panic!("Expected String for public key");
1118 }
1119
1120 if let Value::String(sk) = private_key {
1121 assert_eq!(sk.as_str().len(), 64);
1122 } else {
1123 panic!("Expected String for private key");
1124 }
1125 }
1126 }
1127
1128 #[test]
1129 fn test_ed25519_sign_ffi() {
1130 unsafe {
1131 let stack = crate::stack::alloc_test_stack();
1132
1133 let signing_key = SigningKey::generate(&mut OsRng);
1135 let private_hex = hex::encode(signing_key.to_bytes());
1136
1137 let stack = push(
1138 stack,
1139 Value::String(global_string("Test message".to_string())),
1140 );
1141 let stack = push(stack, Value::String(global_string(private_hex)));
1142
1143 let stack = patch_seq_crypto_ed25519_sign(stack);
1144
1145 let (stack, success) = pop(stack);
1146 let (_, signature) = pop(stack);
1147
1148 assert_eq!(success, Value::Bool(true));
1149 if let Value::String(sig) = signature {
1150 assert_eq!(sig.as_str().len(), 128); } else {
1152 panic!("Expected String for signature");
1153 }
1154 }
1155 }
1156
1157 #[test]
1158 fn test_ed25519_verify_ffi() {
1159 unsafe {
1160 let stack = crate::stack::alloc_test_stack();
1161
1162 let signing_key = SigningKey::generate(&mut OsRng);
1164 let verifying_key = signing_key.verifying_key();
1165
1166 let private_hex = hex::encode(signing_key.to_bytes());
1167 let public_hex = hex::encode(verifying_key.to_bytes());
1168
1169 let message = "Verify this message";
1170 let signature = ed25519_sign(message, &private_hex).unwrap();
1171
1172 let stack = push(stack, Value::String(global_string(message.to_string())));
1173 let stack = push(stack, Value::String(global_string(signature)));
1174 let stack = push(stack, Value::String(global_string(public_hex)));
1175
1176 let stack = patch_seq_crypto_ed25519_verify(stack);
1177
1178 let (_, valid) = pop(stack);
1179 assert_eq!(valid, Value::Bool(true));
1180 }
1181 }
1182
1183 #[test]
1184 fn test_random_int_basic() {
1185 unsafe {
1186 let stack = crate::stack::alloc_test_stack();
1187 let stack = push(stack, Value::Int(1));
1188 let stack = push(stack, Value::Int(100));
1189 let stack = patch_seq_random_int(stack);
1190 let (_, value) = pop(stack);
1191
1192 match value {
1193 Value::Int(n) => {
1194 assert!((1..100).contains(&n), "Expected 1 <= {} < 100", n);
1195 }
1196 _ => panic!("Expected Int"),
1197 }
1198 }
1199 }
1200
1201 #[test]
1202 fn test_random_int_same_min_max() {
1203 unsafe {
1204 let stack = crate::stack::alloc_test_stack();
1205 let stack = push(stack, Value::Int(5));
1206 let stack = push(stack, Value::Int(5));
1207 let stack = patch_seq_random_int(stack);
1208 let (_, value) = pop(stack);
1209
1210 match value {
1211 Value::Int(n) => assert_eq!(n, 5),
1212 _ => panic!("Expected Int"),
1213 }
1214 }
1215 }
1216
1217 #[test]
1218 fn test_random_int_inverted_range() {
1219 unsafe {
1220 let stack = crate::stack::alloc_test_stack();
1221 let stack = push(stack, Value::Int(10));
1222 let stack = push(stack, Value::Int(5));
1223 let stack = patch_seq_random_int(stack);
1224 let (_, value) = pop(stack);
1225
1226 match value {
1227 Value::Int(n) => assert_eq!(n, 10), _ => panic!("Expected Int"),
1229 }
1230 }
1231 }
1232
1233 #[test]
1234 fn test_random_int_small_range() {
1235 unsafe {
1236 let stack = crate::stack::alloc_test_stack();
1237 let stack = push(stack, Value::Int(0));
1238 let stack = push(stack, Value::Int(2));
1239 let stack = patch_seq_random_int(stack);
1240 let (_, value) = pop(stack);
1241
1242 match value {
1243 Value::Int(n) => assert!((0..2).contains(&n), "Expected 0 <= {} < 2", n),
1244 _ => panic!("Expected Int"),
1245 }
1246 }
1247 }
1248
1249 #[test]
1250 fn test_random_int_negative_range() {
1251 unsafe {
1252 let stack = crate::stack::alloc_test_stack();
1253 let stack = push(stack, Value::Int(-10));
1254 let stack = push(stack, Value::Int(10));
1255 let stack = patch_seq_random_int(stack);
1256 let (_, value) = pop(stack);
1257
1258 match value {
1259 Value::Int(n) => assert!((-10..10).contains(&n), "Expected -10 <= {} < 10", n),
1260 _ => panic!("Expected Int"),
1261 }
1262 }
1263 }
1264
1265 #[test]
1266 fn test_random_int_large_range() {
1267 unsafe {
1268 let stack = crate::stack::alloc_test_stack();
1269 let stack = push(stack, Value::Int(0));
1270 let stack = push(stack, Value::Int(i64::MAX));
1271 let stack = patch_seq_random_int(stack);
1272 let (_, value) = pop(stack);
1273
1274 match value {
1275 Value::Int(n) => assert!(n >= 0, "Expected {} >= 0", n),
1276 _ => panic!("Expected Int"),
1277 }
1278 }
1279 }
1280
1281 #[test]
1282 fn test_random_int_extreme_range() {
1283 unsafe {
1285 let stack = crate::stack::alloc_test_stack();
1286 let stack = push(stack, Value::Int(i64::MIN));
1287 let stack = push(stack, Value::Int(i64::MAX));
1288 let stack = patch_seq_random_int(stack);
1289 let (_, value) = pop(stack);
1290
1291 match value {
1292 Value::Int(_) => {} _ => panic!("Expected Int"),
1294 }
1295 }
1296 }
1297
1298 #[test]
1299 fn test_random_int_uniformity() {
1300 let mut buckets = [0u32; 10];
1303 let samples = 10000;
1304
1305 unsafe {
1306 for _ in 0..samples {
1307 let stack = crate::stack::alloc_test_stack();
1308 let stack = push(stack, Value::Int(0));
1309 let stack = push(stack, Value::Int(10));
1310 let stack = patch_seq_random_int(stack);
1311 let (_, value) = pop(stack);
1312
1313 if let Value::Int(n) = value {
1314 buckets[n as usize] += 1;
1315 }
1316 }
1317 }
1318
1319 let expected = samples as u32 / 10;
1322 let tolerance = expected * 30 / 100;
1323
1324 for (i, &count) in buckets.iter().enumerate() {
1325 assert!(
1326 count >= expected - tolerance && count <= expected + tolerance,
1327 "Bucket {} has {} samples, expected {} ± {} (uniformity test)",
1328 i,
1329 count,
1330 expected,
1331 tolerance
1332 );
1333 }
1334 }
1335}