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 sha2::{Digest, Sha256};
43use subtle::ConstantTimeEq;
44use uuid::Uuid;
45
46const AES_NONCE_SIZE: usize = 12;
47const AES_KEY_SIZE: usize = 32;
48const AES_GCM_TAG_SIZE: usize = 16;
49const MIN_PBKDF2_ITERATIONS: i64 = 1_000;
50
51type HmacSha256 = Hmac<Sha256>;
52
53#[unsafe(no_mangle)]
62pub unsafe extern "C" fn patch_seq_sha256(stack: Stack) -> Stack {
63 assert!(!stack.is_null(), "sha256: stack is empty");
64
65 let (stack, value) = unsafe { pop(stack) };
66
67 match value {
68 Value::String(s) => {
69 let mut hasher = Sha256::new();
70 hasher.update(s.as_str().as_bytes());
71 let result = hasher.finalize();
72 let hex_digest = hex::encode(result);
73 unsafe { push(stack, Value::String(global_string(hex_digest))) }
74 }
75 _ => panic!("sha256: expected String on stack, got {:?}", value),
76 }
77}
78
79#[unsafe(no_mangle)]
89pub unsafe extern "C" fn patch_seq_hmac_sha256(stack: Stack) -> Stack {
90 assert!(!stack.is_null(), "hmac-sha256: stack is empty");
91
92 let (stack, key_value) = unsafe { pop(stack) };
93 let (stack, msg_value) = unsafe { pop(stack) };
94
95 match (msg_value, key_value) {
96 (Value::String(msg), Value::String(key)) => {
97 let mut mac = <HmacSha256 as Mac>::new_from_slice(key.as_str().as_bytes())
98 .expect("HMAC can take any key");
99 mac.update(msg.as_str().as_bytes());
100 let result = mac.finalize();
101 let hex_sig = hex::encode(result.into_bytes());
102 unsafe { push(stack, Value::String(global_string(hex_sig))) }
103 }
104 (msg, key) => panic!(
105 "hmac-sha256: expected (String, String) on stack, got ({:?}, {:?})",
106 msg, key
107 ),
108 }
109}
110
111#[unsafe(no_mangle)]
125pub unsafe extern "C" fn patch_seq_constant_time_eq(stack: Stack) -> Stack {
126 assert!(!stack.is_null(), "constant-time-eq: stack is empty");
127
128 let (stack, b_value) = unsafe { pop(stack) };
129 let (stack, a_value) = unsafe { pop(stack) };
130
131 match (a_value, b_value) {
132 (Value::String(a), Value::String(b)) => {
133 let a_bytes = a.as_str().as_bytes();
134 let b_bytes = b.as_str().as_bytes();
135
136 let eq = a_bytes.ct_eq(b_bytes);
139
140 unsafe { push(stack, Value::Bool(bool::from(eq))) }
141 }
142 (a, b) => panic!(
143 "constant-time-eq: expected (String, String) on stack, got ({:?}, {:?})",
144 a, b
145 ),
146 }
147}
148
149#[unsafe(no_mangle)]
163pub unsafe extern "C" fn patch_seq_random_bytes(stack: Stack) -> Stack {
164 assert!(!stack.is_null(), "random-bytes: stack is empty");
165
166 let (stack, value) = unsafe { pop(stack) };
167
168 match value {
169 Value::Int(n) => {
170 if n < 0 {
171 panic!("random-bytes: byte count must be non-negative, got {}", n);
172 }
173 if n > 1024 {
174 panic!("random-bytes: byte count too large (max 1024), got {}", n);
175 }
176
177 let mut bytes = vec![0u8; n as usize];
178 rand::thread_rng().fill_bytes(&mut bytes);
179 let hex_str = hex::encode(&bytes);
180 unsafe { push(stack, Value::String(global_string(hex_str))) }
181 }
182 _ => panic!("random-bytes: expected Int on stack, got {:?}", value),
183 }
184}
185
186#[unsafe(no_mangle)]
195pub unsafe extern "C" fn patch_seq_uuid4(stack: Stack) -> Stack {
196 assert!(!stack.is_null(), "uuid4: stack is empty");
197
198 let uuid = Uuid::new_v4();
199 unsafe { push(stack, Value::String(global_string(uuid.to_string()))) }
200}
201
202#[unsafe(no_mangle)]
217pub unsafe extern "C" fn patch_seq_crypto_aes_gcm_encrypt(stack: Stack) -> Stack {
218 assert!(!stack.is_null(), "crypto.aes-gcm-encrypt: stack is null");
219
220 let (stack, key_val) = unsafe { pop(stack) };
221 let (stack, plaintext_val) = unsafe { pop(stack) };
222
223 match (plaintext_val, key_val) {
224 (Value::String(plaintext), Value::String(key_hex)) => {
225 match aes_gcm_encrypt(plaintext.as_str(), key_hex.as_str()) {
226 Some(ciphertext) => {
227 let stack = unsafe { push(stack, Value::String(global_string(ciphertext))) };
228 unsafe { push(stack, Value::Bool(true)) }
229 }
230 None => {
231 let stack = unsafe { push(stack, Value::String(global_string(String::new()))) };
232 unsafe { push(stack, Value::Bool(false)) }
233 }
234 }
235 }
236 _ => panic!("crypto.aes-gcm-encrypt: expected two Strings on stack"),
237 }
238}
239
240#[unsafe(no_mangle)]
255pub unsafe extern "C" fn patch_seq_crypto_aes_gcm_decrypt(stack: Stack) -> Stack {
256 assert!(!stack.is_null(), "crypto.aes-gcm-decrypt: stack is null");
257
258 let (stack, key_val) = unsafe { pop(stack) };
259 let (stack, ciphertext_val) = unsafe { pop(stack) };
260
261 match (ciphertext_val, key_val) {
262 (Value::String(ciphertext), Value::String(key_hex)) => {
263 match aes_gcm_decrypt(ciphertext.as_str(), key_hex.as_str()) {
264 Some(plaintext) => {
265 let stack = unsafe { push(stack, Value::String(global_string(plaintext))) };
266 unsafe { push(stack, Value::Bool(true)) }
267 }
268 None => {
269 let stack = unsafe { push(stack, Value::String(global_string(String::new()))) };
270 unsafe { push(stack, Value::Bool(false)) }
271 }
272 }
273 }
274 _ => panic!("crypto.aes-gcm-decrypt: expected two Strings on stack"),
275 }
276}
277
278#[unsafe(no_mangle)]
294pub unsafe extern "C" fn patch_seq_crypto_pbkdf2_sha256(stack: Stack) -> Stack {
295 assert!(!stack.is_null(), "crypto.pbkdf2-sha256: stack is null");
296
297 let (stack, iterations_val) = unsafe { pop(stack) };
298 let (stack, salt_val) = unsafe { pop(stack) };
299 let (stack, password_val) = unsafe { pop(stack) };
300
301 match (password_val, salt_val, iterations_val) {
302 (Value::String(password), Value::String(salt), Value::Int(iterations)) => {
303 if iterations < MIN_PBKDF2_ITERATIONS {
305 let stack = unsafe { push(stack, Value::String(global_string(String::new()))) };
306 return unsafe { push(stack, Value::Bool(false)) };
307 }
308
309 let key = derive_key_pbkdf2(password.as_str(), salt.as_str(), iterations as u32);
310 let key_hex = hex::encode(key);
311 let stack = unsafe { push(stack, Value::String(global_string(key_hex))) };
312 unsafe { push(stack, Value::Bool(true)) }
313 }
314 _ => panic!("crypto.pbkdf2-sha256: expected String, String, Int on stack"),
315 }
316}
317
318fn aes_gcm_encrypt(plaintext: &str, key_hex: &str) -> Option<String> {
321 let key_bytes = hex::decode(key_hex).ok()?;
323 if key_bytes.len() != AES_KEY_SIZE {
324 return None;
325 }
326
327 let cipher = Aes256Gcm::new_from_slice(&key_bytes).ok()?;
329
330 let mut nonce_bytes = [0u8; AES_NONCE_SIZE];
332 OsRng.fill_bytes(&mut nonce_bytes);
333 let nonce = Nonce::from_slice(&nonce_bytes);
334
335 let ciphertext = cipher.encrypt(nonce, plaintext.as_bytes()).ok()?;
337
338 let mut combined = Vec::with_capacity(AES_NONCE_SIZE + ciphertext.len());
340 combined.extend_from_slice(&nonce_bytes);
341 combined.extend_from_slice(&ciphertext);
342
343 Some(STANDARD.encode(&combined))
344}
345
346fn aes_gcm_decrypt(ciphertext_b64: &str, key_hex: &str) -> Option<String> {
347 let combined = STANDARD.decode(ciphertext_b64).ok()?;
349 if combined.len() < AES_NONCE_SIZE + AES_GCM_TAG_SIZE {
350 return None;
352 }
353
354 let key_bytes = hex::decode(key_hex).ok()?;
356 if key_bytes.len() != AES_KEY_SIZE {
357 return None;
358 }
359
360 let (nonce_bytes, ciphertext) = combined.split_at(AES_NONCE_SIZE);
362 let nonce = Nonce::from_slice(nonce_bytes);
363
364 let cipher = Aes256Gcm::new_from_slice(&key_bytes).ok()?;
366 let plaintext_bytes = cipher.decrypt(nonce, ciphertext).ok()?;
367
368 String::from_utf8(plaintext_bytes).ok()
369}
370
371fn derive_key_pbkdf2(password: &str, salt: &str, iterations: u32) -> [u8; AES_KEY_SIZE] {
372 let mut key = [0u8; AES_KEY_SIZE];
373 pbkdf2::pbkdf2_hmac::<Sha256>(password.as_bytes(), salt.as_bytes(), iterations, &mut key);
374 key
375}
376
377#[unsafe(no_mangle)]
392pub unsafe extern "C" fn patch_seq_crypto_ed25519_keypair(stack: Stack) -> Stack {
393 assert!(!stack.is_null(), "crypto.ed25519-keypair: stack is null");
394
395 let signing_key = SigningKey::generate(&mut OsRng);
396 let verifying_key = signing_key.verifying_key();
397
398 let private_hex = hex::encode(signing_key.to_bytes());
399 let public_hex = hex::encode(verifying_key.to_bytes());
400
401 let stack = unsafe { push(stack, Value::String(global_string(public_hex))) };
402 unsafe { push(stack, Value::String(global_string(private_hex))) }
403}
404
405#[unsafe(no_mangle)]
420pub unsafe extern "C" fn patch_seq_crypto_ed25519_sign(stack: Stack) -> Stack {
421 assert!(!stack.is_null(), "crypto.ed25519-sign: stack is null");
422
423 let (stack, key_val) = unsafe { pop(stack) };
424 let (stack, msg_val) = unsafe { pop(stack) };
425
426 match (msg_val, key_val) {
427 (Value::String(message), Value::String(private_key_hex)) => {
428 match ed25519_sign(message.as_str(), private_key_hex.as_str()) {
429 Some(signature) => {
430 let stack = unsafe { push(stack, Value::String(global_string(signature))) };
431 unsafe { push(stack, Value::Bool(true)) }
432 }
433 None => {
434 let stack = unsafe { push(stack, Value::String(global_string(String::new()))) };
435 unsafe { push(stack, Value::Bool(false)) }
436 }
437 }
438 }
439 _ => panic!("crypto.ed25519-sign: expected String, String on stack"),
440 }
441}
442
443#[unsafe(no_mangle)]
458pub unsafe extern "C" fn patch_seq_crypto_ed25519_verify(stack: Stack) -> Stack {
459 assert!(!stack.is_null(), "crypto.ed25519-verify: stack is null");
460
461 let (stack, pubkey_val) = unsafe { pop(stack) };
462 let (stack, sig_val) = unsafe { pop(stack) };
463 let (stack, msg_val) = unsafe { pop(stack) };
464
465 match (msg_val, sig_val, pubkey_val) {
466 (Value::String(message), Value::String(signature_hex), Value::String(public_key_hex)) => {
467 let valid = ed25519_verify(
468 message.as_str(),
469 signature_hex.as_str(),
470 public_key_hex.as_str(),
471 );
472 unsafe { push(stack, Value::Bool(valid)) }
473 }
474 _ => panic!("crypto.ed25519-verify: expected String, String, String on stack"),
475 }
476}
477
478fn ed25519_sign(message: &str, private_key_hex: &str) -> Option<String> {
481 let key_bytes = hex::decode(private_key_hex).ok()?;
482 if key_bytes.len() != 32 {
483 return None;
484 }
485
486 let key_array: [u8; 32] = key_bytes.try_into().ok()?;
487 let signing_key = SigningKey::from_bytes(&key_array);
488 let signature = signing_key.sign(message.as_bytes());
489
490 Some(hex::encode(signature.to_bytes()))
491}
492
493fn ed25519_verify(message: &str, signature_hex: &str, public_key_hex: &str) -> bool {
494 let verify_inner = || -> Option<bool> {
495 let sig_bytes = hex::decode(signature_hex).ok()?;
496 if sig_bytes.len() != 64 {
497 return Some(false);
498 }
499
500 let pubkey_bytes = hex::decode(public_key_hex).ok()?;
501 if pubkey_bytes.len() != 32 {
502 return Some(false);
503 }
504
505 let sig_array: [u8; 64] = sig_bytes.try_into().ok()?;
506 let pubkey_array: [u8; 32] = pubkey_bytes.try_into().ok()?;
507
508 let signature = Signature::from_bytes(&sig_array);
509 let verifying_key = VerifyingKey::from_bytes(&pubkey_array).ok()?;
510
511 Some(verifying_key.verify(message.as_bytes(), &signature).is_ok())
512 };
513
514 verify_inner().unwrap_or(false)
515}
516
517#[cfg(test)]
518mod tests {
519 use super::*;
520 use crate::stack::pop;
521
522 #[test]
523 fn test_sha256() {
524 unsafe {
525 let stack = crate::stack::alloc_test_stack();
526 let stack = push(stack, Value::String(global_string("hello".to_string())));
527 let stack = patch_seq_sha256(stack);
528 let (_, value) = pop(stack);
529
530 match value {
531 Value::String(s) => {
532 assert_eq!(
534 s.as_str(),
535 "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
536 );
537 }
538 _ => panic!("Expected String"),
539 }
540 }
541 }
542
543 #[test]
544 fn test_sha256_empty() {
545 unsafe {
546 let stack = crate::stack::alloc_test_stack();
547 let stack = push(stack, Value::String(global_string(String::new())));
548 let stack = patch_seq_sha256(stack);
549 let (_, value) = pop(stack);
550
551 match value {
552 Value::String(s) => {
553 assert_eq!(
555 s.as_str(),
556 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
557 );
558 }
559 _ => panic!("Expected String"),
560 }
561 }
562 }
563
564 #[test]
565 fn test_hmac_sha256() {
566 unsafe {
567 let stack = crate::stack::alloc_test_stack();
568 let stack = push(stack, Value::String(global_string("message".to_string())));
569 let stack = push(stack, Value::String(global_string("secret".to_string())));
570 let stack = patch_seq_hmac_sha256(stack);
571 let (_, value) = pop(stack);
572
573 match value {
574 Value::String(s) => {
575 assert_eq!(
577 s.as_str(),
578 "8b5f48702995c1598c573db1e21866a9b825d4a794d169d7060a03605796360b"
579 );
580 }
581 _ => panic!("Expected String"),
582 }
583 }
584 }
585
586 #[test]
587 fn test_constant_time_eq_equal() {
588 unsafe {
589 let stack = crate::stack::alloc_test_stack();
590 let stack = push(stack, Value::String(global_string("hello".to_string())));
591 let stack = push(stack, Value::String(global_string("hello".to_string())));
592 let stack = patch_seq_constant_time_eq(stack);
593 let (_, value) = pop(stack);
594
595 match value {
596 Value::Bool(b) => assert!(b),
597 _ => panic!("Expected Bool"),
598 }
599 }
600 }
601
602 #[test]
603 fn test_constant_time_eq_different() {
604 unsafe {
605 let stack = crate::stack::alloc_test_stack();
606 let stack = push(stack, Value::String(global_string("hello".to_string())));
607 let stack = push(stack, Value::String(global_string("world".to_string())));
608 let stack = patch_seq_constant_time_eq(stack);
609 let (_, value) = pop(stack);
610
611 match value {
612 Value::Bool(b) => assert!(!b),
613 _ => panic!("Expected Bool"),
614 }
615 }
616 }
617
618 #[test]
619 fn test_constant_time_eq_different_lengths() {
620 unsafe {
621 let stack = crate::stack::alloc_test_stack();
622 let stack = push(stack, Value::String(global_string("hello".to_string())));
623 let stack = push(stack, Value::String(global_string("hi".to_string())));
624 let stack = patch_seq_constant_time_eq(stack);
625 let (_, value) = pop(stack);
626
627 match value {
628 Value::Bool(b) => assert!(!b),
629 _ => panic!("Expected Bool"),
630 }
631 }
632 }
633
634 #[test]
635 fn test_random_bytes() {
636 unsafe {
637 let stack = crate::stack::alloc_test_stack();
638 let stack = push(stack, Value::Int(16));
639 let stack = patch_seq_random_bytes(stack);
640 let (_, value) = pop(stack);
641
642 match value {
643 Value::String(s) => {
644 assert_eq!(s.as_str().len(), 32);
646 assert!(hex::decode(s.as_str()).is_ok());
648 }
649 _ => panic!("Expected String"),
650 }
651 }
652 }
653
654 #[test]
655 fn test_random_bytes_zero() {
656 unsafe {
657 let stack = crate::stack::alloc_test_stack();
658 let stack = push(stack, Value::Int(0));
659 let stack = patch_seq_random_bytes(stack);
660 let (_, value) = pop(stack);
661
662 match value {
663 Value::String(s) => {
664 assert_eq!(s.as_str(), "");
665 }
666 _ => panic!("Expected String"),
667 }
668 }
669 }
670
671 #[test]
672 fn test_uuid4() {
673 unsafe {
674 let stack = crate::stack::alloc_test_stack();
675 let stack = patch_seq_uuid4(stack);
676 let (_, value) = pop(stack);
677
678 match value {
679 Value::String(s) => {
680 assert_eq!(s.as_str().len(), 36);
682 assert_eq!(s.as_str().chars().filter(|c| *c == '-').count(), 4);
683 assert_eq!(s.as_str().chars().nth(14), Some('4'));
685 }
686 _ => panic!("Expected String"),
687 }
688 }
689 }
690
691 #[test]
692 fn test_uuid4_unique() {
693 unsafe {
694 let stack = crate::stack::alloc_test_stack();
695 let stack = patch_seq_uuid4(stack);
696 let (stack, value1) = pop(stack);
697 let stack = patch_seq_uuid4(stack);
698 let (_, value2) = pop(stack);
699
700 match (value1, value2) {
701 (Value::String(s1), Value::String(s2)) => {
702 assert_ne!(s1.as_str(), s2.as_str());
703 }
704 _ => panic!("Expected Strings"),
705 }
706 }
707 }
708
709 #[test]
710 fn test_random_bytes_max_limit() {
711 unsafe {
712 let stack = crate::stack::alloc_test_stack();
713 let stack = push(stack, Value::Int(1024)); let stack = patch_seq_random_bytes(stack);
715 let (_, value) = pop(stack);
716
717 match value {
718 Value::String(s) => {
719 assert_eq!(s.as_str().len(), 2048);
721 }
722 _ => panic!("Expected String"),
723 }
724 }
725 }
726 #[test]
732 fn test_aes_gcm_roundtrip() {
733 unsafe {
734 let stack = crate::stack::alloc_test_stack();
735
736 let key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
738
739 let stack = push(
740 stack,
741 Value::String(global_string("hello world".to_string())),
742 );
743 let stack = push(stack, Value::String(global_string(key_hex.to_string())));
744
745 let stack = patch_seq_crypto_aes_gcm_encrypt(stack);
747
748 let (stack, success) = pop(stack);
750 assert_eq!(success, Value::Bool(true));
751
752 let stack = push(stack, Value::String(global_string(key_hex.to_string())));
754
755 let stack = patch_seq_crypto_aes_gcm_decrypt(stack);
757
758 let (stack, success) = pop(stack);
760 assert_eq!(success, Value::Bool(true));
761
762 let (_, result) = pop(stack);
764 if let Value::String(s) = result {
765 assert_eq!(s.as_str(), "hello world");
766 } else {
767 panic!("expected string");
768 }
769 }
770 }
771
772 #[test]
773 fn test_aes_gcm_wrong_key() {
774 unsafe {
775 let stack = crate::stack::alloc_test_stack();
776
777 let key1 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
778 let key2 = "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210";
779
780 let stack = push(
781 stack,
782 Value::String(global_string("secret message".to_string())),
783 );
784 let stack = push(stack, Value::String(global_string(key1.to_string())));
785
786 let stack = patch_seq_crypto_aes_gcm_encrypt(stack);
788 let (stack, success) = pop(stack);
789 assert_eq!(success, Value::Bool(true));
790
791 let stack = push(stack, Value::String(global_string(key2.to_string())));
793 let stack = patch_seq_crypto_aes_gcm_decrypt(stack);
794
795 let (_, success) = pop(stack);
797 assert_eq!(success, Value::Bool(false));
798 }
799 }
800
801 #[test]
802 fn test_aes_gcm_invalid_key_length() {
803 unsafe {
804 let stack = crate::stack::alloc_test_stack();
805
806 let short_key = "0123456789abcdef";
808
809 let stack = push(stack, Value::String(global_string("test data".to_string())));
810 let stack = push(stack, Value::String(global_string(short_key.to_string())));
811
812 let stack = patch_seq_crypto_aes_gcm_encrypt(stack);
813 let (_, success) = pop(stack);
814 assert_eq!(success, Value::Bool(false));
815 }
816 }
817
818 #[test]
819 fn test_aes_gcm_invalid_ciphertext() {
820 unsafe {
821 let stack = crate::stack::alloc_test_stack();
822
823 let key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
824
825 let stack = push(
827 stack,
828 Value::String(global_string("not-valid-base64!!!".to_string())),
829 );
830 let stack = push(stack, Value::String(global_string(key.to_string())));
831
832 let stack = patch_seq_crypto_aes_gcm_decrypt(stack);
833 let (_, success) = pop(stack);
834 assert_eq!(success, Value::Bool(false));
835 }
836 }
837
838 #[test]
839 fn test_aes_gcm_empty_plaintext() {
840 let key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
841
842 let ciphertext = aes_gcm_encrypt("", key).unwrap();
843 let decrypted = aes_gcm_decrypt(&ciphertext, key).unwrap();
844 assert_eq!(decrypted, "");
845 }
846
847 #[test]
848 fn test_aes_gcm_special_characters() {
849 let key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
850 let plaintext = "Hello\nWorld\tTab\"Quote\\Backslash";
851
852 let ciphertext = aes_gcm_encrypt(plaintext, key).unwrap();
853 let decrypted = aes_gcm_decrypt(&ciphertext, key).unwrap();
854 assert_eq!(decrypted, plaintext);
855 }
856
857 #[test]
860 fn test_pbkdf2_sha256() {
861 unsafe {
862 let stack = crate::stack::alloc_test_stack();
863
864 let stack = push(
865 stack,
866 Value::String(global_string("my-password".to_string())),
867 );
868 let stack = push(
869 stack,
870 Value::String(global_string("random-salt".to_string())),
871 );
872 let stack = push(stack, Value::Int(10000));
873
874 let stack = patch_seq_crypto_pbkdf2_sha256(stack);
875
876 let (stack, success) = pop(stack);
878 assert_eq!(success, Value::Bool(true));
879
880 let (_, result) = pop(stack);
882 if let Value::String(s) = result {
883 assert_eq!(s.as_str().len(), 64);
884 assert!(hex::decode(s.as_str()).is_ok());
886 } else {
887 panic!("expected string");
888 }
889 }
890 }
891
892 #[test]
893 fn test_pbkdf2_deterministic() {
894 let key1 = derive_key_pbkdf2("password", "salt", 10000);
896 let key2 = derive_key_pbkdf2("password", "salt", 10000);
897 assert_eq!(key1, key2);
898
899 let key3 = derive_key_pbkdf2("password", "different-salt", 10000);
901 assert_ne!(key1, key3);
902 }
903
904 #[test]
905 fn test_pbkdf2_invalid_iterations() {
906 unsafe {
907 let stack = crate::stack::alloc_test_stack();
908
909 let stack = push(stack, Value::String(global_string("password".to_string())));
910 let stack = push(stack, Value::String(global_string("salt".to_string())));
911 let stack = push(stack, Value::Int(0)); let stack = patch_seq_crypto_pbkdf2_sha256(stack);
914
915 let (_, success) = pop(stack);
916 assert_eq!(success, Value::Bool(false));
917 }
918 }
919
920 #[test]
921 fn test_encrypt_decrypt_with_derived_key() {
922 let password = "user-secret-password";
924 let salt = "unique-user-salt";
925 let iterations = 10000u32;
926
927 let key = derive_key_pbkdf2(password, salt, iterations);
929 let key_hex = hex::encode(key);
930
931 let plaintext = "sensitive data to protect";
933 let ciphertext = aes_gcm_encrypt(plaintext, &key_hex).unwrap();
934
935 let decrypted = aes_gcm_decrypt(&ciphertext, &key_hex).unwrap();
937 assert_eq!(decrypted, plaintext);
938 }
939
940 #[test]
943 fn test_ed25519_sign_verify() {
944 let message = "Hello, World!";
945
946 let signing_key = SigningKey::generate(&mut OsRng);
948 let verifying_key = signing_key.verifying_key();
949
950 let private_hex = hex::encode(signing_key.to_bytes());
951 let public_hex = hex::encode(verifying_key.to_bytes());
952
953 let signature = ed25519_sign(message, &private_hex).unwrap();
955 assert_eq!(signature.len(), 128); assert!(ed25519_verify(message, &signature, &public_hex));
959 }
960
961 #[test]
962 fn test_ed25519_wrong_message() {
963 let message = "Original message";
964 let wrong_message = "Wrong message";
965
966 let signing_key = SigningKey::generate(&mut OsRng);
967 let verifying_key = signing_key.verifying_key();
968
969 let private_hex = hex::encode(signing_key.to_bytes());
970 let public_hex = hex::encode(verifying_key.to_bytes());
971
972 let signature = ed25519_sign(message, &private_hex).unwrap();
973
974 assert!(!ed25519_verify(wrong_message, &signature, &public_hex));
976 }
977
978 #[test]
979 fn test_ed25519_wrong_key() {
980 let message = "Test message";
981
982 let signing_key1 = SigningKey::generate(&mut OsRng);
983 let signing_key2 = SigningKey::generate(&mut OsRng);
984
985 let private_hex = hex::encode(signing_key1.to_bytes());
986 let wrong_public_hex = hex::encode(signing_key2.verifying_key().to_bytes());
987
988 let signature = ed25519_sign(message, &private_hex).unwrap();
989
990 assert!(!ed25519_verify(message, &signature, &wrong_public_hex));
992 }
993
994 #[test]
995 fn test_ed25519_invalid_key_length() {
996 let message = "Test message";
997 let invalid_key = "tooshort";
998
999 assert!(ed25519_sign(message, invalid_key).is_none());
1001 }
1002
1003 #[test]
1004 fn test_ed25519_invalid_signature() {
1005 let message = "Test message";
1006
1007 let signing_key = SigningKey::generate(&mut OsRng);
1008 let public_hex = hex::encode(signing_key.verifying_key().to_bytes());
1009
1010 let invalid_signature = "0".repeat(128); assert!(!ed25519_verify(message, &invalid_signature, &public_hex));
1014 }
1015
1016 #[test]
1017 fn test_ed25519_empty_message() {
1018 let message = "";
1019
1020 let signing_key = SigningKey::generate(&mut OsRng);
1021 let verifying_key = signing_key.verifying_key();
1022
1023 let private_hex = hex::encode(signing_key.to_bytes());
1024 let public_hex = hex::encode(verifying_key.to_bytes());
1025
1026 let signature = ed25519_sign(message, &private_hex).unwrap();
1028
1029 assert!(ed25519_verify(message, &signature, &public_hex));
1031 }
1032
1033 #[test]
1034 fn test_ed25519_keypair_ffi() {
1035 unsafe {
1036 let stack = crate::stack::alloc_test_stack();
1037
1038 let stack = patch_seq_crypto_ed25519_keypair(stack);
1039
1040 let (stack, private_key) = pop(stack);
1041 let (_, public_key) = pop(stack);
1042
1043 if let Value::String(pk) = public_key {
1045 assert_eq!(pk.as_str().len(), 64);
1046 } else {
1047 panic!("Expected String for public key");
1048 }
1049
1050 if let Value::String(sk) = private_key {
1051 assert_eq!(sk.as_str().len(), 64);
1052 } else {
1053 panic!("Expected String for private key");
1054 }
1055 }
1056 }
1057
1058 #[test]
1059 fn test_ed25519_sign_ffi() {
1060 unsafe {
1061 let stack = crate::stack::alloc_test_stack();
1062
1063 let signing_key = SigningKey::generate(&mut OsRng);
1065 let private_hex = hex::encode(signing_key.to_bytes());
1066
1067 let stack = push(
1068 stack,
1069 Value::String(global_string("Test message".to_string())),
1070 );
1071 let stack = push(stack, Value::String(global_string(private_hex)));
1072
1073 let stack = patch_seq_crypto_ed25519_sign(stack);
1074
1075 let (stack, success) = pop(stack);
1076 let (_, signature) = pop(stack);
1077
1078 assert_eq!(success, Value::Bool(true));
1079 if let Value::String(sig) = signature {
1080 assert_eq!(sig.as_str().len(), 128); } else {
1082 panic!("Expected String for signature");
1083 }
1084 }
1085 }
1086
1087 #[test]
1088 fn test_ed25519_verify_ffi() {
1089 unsafe {
1090 let stack = crate::stack::alloc_test_stack();
1091
1092 let signing_key = SigningKey::generate(&mut OsRng);
1094 let verifying_key = signing_key.verifying_key();
1095
1096 let private_hex = hex::encode(signing_key.to_bytes());
1097 let public_hex = hex::encode(verifying_key.to_bytes());
1098
1099 let message = "Verify this message";
1100 let signature = ed25519_sign(message, &private_hex).unwrap();
1101
1102 let stack = push(stack, Value::String(global_string(message.to_string())));
1103 let stack = push(stack, Value::String(global_string(signature)));
1104 let stack = push(stack, Value::String(global_string(public_hex)));
1105
1106 let stack = patch_seq_crypto_ed25519_verify(stack);
1107
1108 let (_, valid) = pop(stack);
1109 assert_eq!(valid, Value::Bool(true));
1110 }
1111 }
1112}