use super::aes::{aes_gcm_decrypt, aes_gcm_encrypt};
use super::ed25519::{ed25519_sign, ed25519_verify};
use super::pbkdf::derive_key_pbkdf2;
use super::*;
use crate::seqstring::global_string;
use crate::stack::{pop, push};
use crate::value::Value;
use ::ed25519_dalek::SigningKey;
use aes_gcm::aead::OsRng;
#[test]
fn test_sha256() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::String(global_string("hello".to_string())));
let stack = patch_seq_sha256(stack);
let (_, value) = pop(stack);
match value {
Value::String(s) => {
assert_eq!(
s.as_str(),
"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
);
}
_ => panic!("Expected String"),
}
}
}
#[test]
fn test_sha256_empty() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::String(global_string(String::new())));
let stack = patch_seq_sha256(stack);
let (_, value) = pop(stack);
match value {
Value::String(s) => {
assert_eq!(
s.as_str(),
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
);
}
_ => panic!("Expected String"),
}
}
}
#[test]
fn test_hmac_sha256() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::String(global_string("message".to_string())));
let stack = push(stack, Value::String(global_string("secret".to_string())));
let stack = patch_seq_hmac_sha256(stack);
let (_, value) = pop(stack);
match value {
Value::String(s) => {
assert_eq!(
s.as_str(),
"8b5f48702995c1598c573db1e21866a9b825d4a794d169d7060a03605796360b"
);
}
_ => panic!("Expected String"),
}
}
}
#[test]
fn test_constant_time_eq_equal() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::String(global_string("hello".to_string())));
let stack = push(stack, Value::String(global_string("hello".to_string())));
let stack = patch_seq_constant_time_eq(stack);
let (_, value) = pop(stack);
match value {
Value::Bool(b) => assert!(b),
_ => panic!("Expected Bool"),
}
}
}
#[test]
fn test_constant_time_eq_different() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::String(global_string("hello".to_string())));
let stack = push(stack, Value::String(global_string("world".to_string())));
let stack = patch_seq_constant_time_eq(stack);
let (_, value) = pop(stack);
match value {
Value::Bool(b) => assert!(!b),
_ => panic!("Expected Bool"),
}
}
}
#[test]
fn test_constant_time_eq_different_lengths() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::String(global_string("hello".to_string())));
let stack = push(stack, Value::String(global_string("hi".to_string())));
let stack = patch_seq_constant_time_eq(stack);
let (_, value) = pop(stack);
match value {
Value::Bool(b) => assert!(!b),
_ => panic!("Expected Bool"),
}
}
}
#[test]
fn test_random_bytes() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(16));
let stack = patch_seq_random_bytes(stack);
let (_, value) = pop(stack);
match value {
Value::String(s) => {
assert_eq!(s.as_str().len(), 32);
assert!(hex::decode(s.as_str()).is_ok());
}
_ => panic!("Expected String"),
}
}
}
#[test]
fn test_random_bytes_zero() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(0));
let stack = patch_seq_random_bytes(stack);
let (_, value) = pop(stack);
match value {
Value::String(s) => {
assert_eq!(s.as_str(), "");
}
_ => panic!("Expected String"),
}
}
}
#[test]
fn test_uuid4() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = patch_seq_uuid4(stack);
let (_, value) = pop(stack);
match value {
Value::String(s) => {
assert_eq!(s.as_str().len(), 36);
assert_eq!(s.as_str().chars().filter(|c| *c == '-').count(), 4);
assert_eq!(s.as_str().chars().nth(14), Some('4'));
}
_ => panic!("Expected String"),
}
}
}
#[test]
fn test_uuid4_unique() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = patch_seq_uuid4(stack);
let (stack, value1) = pop(stack);
let stack = patch_seq_uuid4(stack);
let (_, value2) = pop(stack);
match (value1, value2) {
(Value::String(s1), Value::String(s2)) => {
assert_ne!(s1.as_str(), s2.as_str());
}
_ => panic!("Expected Strings"),
}
}
}
#[test]
fn test_random_bytes_max_limit() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(1024)); let stack = patch_seq_random_bytes(stack);
let (_, value) = pop(stack);
match value {
Value::String(s) => {
assert_eq!(s.as_str().len(), 2048);
}
_ => panic!("Expected String"),
}
}
}
#[test]
fn test_aes_gcm_roundtrip() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let stack = push(
stack,
Value::String(global_string("hello world".to_string())),
);
let stack = push(stack, Value::String(global_string(key_hex.to_string())));
let stack = patch_seq_crypto_aes_gcm_encrypt(stack);
let (stack, success) = pop(stack);
assert_eq!(success, Value::Bool(true));
let stack = push(stack, Value::String(global_string(key_hex.to_string())));
let stack = patch_seq_crypto_aes_gcm_decrypt(stack);
let (stack, success) = pop(stack);
assert_eq!(success, Value::Bool(true));
let (_, result) = pop(stack);
if let Value::String(s) = result {
assert_eq!(s.as_str(), "hello world");
} else {
panic!("expected string");
}
}
}
#[test]
fn test_aes_gcm_wrong_key() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let key1 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let key2 = "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210";
let stack = push(
stack,
Value::String(global_string("secret message".to_string())),
);
let stack = push(stack, Value::String(global_string(key1.to_string())));
let stack = patch_seq_crypto_aes_gcm_encrypt(stack);
let (stack, success) = pop(stack);
assert_eq!(success, Value::Bool(true));
let stack = push(stack, Value::String(global_string(key2.to_string())));
let stack = patch_seq_crypto_aes_gcm_decrypt(stack);
let (_, success) = pop(stack);
assert_eq!(success, Value::Bool(false));
}
}
#[test]
fn test_aes_gcm_invalid_key_length() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let short_key = "0123456789abcdef";
let stack = push(stack, Value::String(global_string("test data".to_string())));
let stack = push(stack, Value::String(global_string(short_key.to_string())));
let stack = patch_seq_crypto_aes_gcm_encrypt(stack);
let (_, success) = pop(stack);
assert_eq!(success, Value::Bool(false));
}
}
#[test]
fn test_aes_gcm_invalid_ciphertext() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let stack = push(
stack,
Value::String(global_string("not-valid-base64!!!".to_string())),
);
let stack = push(stack, Value::String(global_string(key.to_string())));
let stack = patch_seq_crypto_aes_gcm_decrypt(stack);
let (_, success) = pop(stack);
assert_eq!(success, Value::Bool(false));
}
}
#[test]
fn test_aes_gcm_empty_plaintext() {
let key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let ciphertext = aes_gcm_encrypt("", key).unwrap();
let decrypted = aes_gcm_decrypt(&ciphertext, key).unwrap();
assert_eq!(decrypted, "");
}
#[test]
fn test_aes_gcm_special_characters() {
let key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
let plaintext = "Hello\nWorld\tTab\"Quote\\Backslash";
let ciphertext = aes_gcm_encrypt(plaintext, key).unwrap();
let decrypted = aes_gcm_decrypt(&ciphertext, key).unwrap();
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_pbkdf2_sha256() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(
stack,
Value::String(global_string("my-password".to_string())),
);
let stack = push(
stack,
Value::String(global_string("random-salt".to_string())),
);
let stack = push(stack, Value::Int(10000));
let stack = patch_seq_crypto_pbkdf2_sha256(stack);
let (stack, success) = pop(stack);
assert_eq!(success, Value::Bool(true));
let (_, result) = pop(stack);
if let Value::String(s) = result {
assert_eq!(s.as_str().len(), 64);
assert!(hex::decode(s.as_str()).is_ok());
} else {
panic!("expected string");
}
}
}
#[test]
fn test_pbkdf2_deterministic() {
let key1 = derive_key_pbkdf2("password", "salt", 10000);
let key2 = derive_key_pbkdf2("password", "salt", 10000);
assert_eq!(key1, key2);
let key3 = derive_key_pbkdf2("password", "different-salt", 10000);
assert_ne!(key1, key3);
}
#[test]
fn test_pbkdf2_invalid_iterations() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::String(global_string("password".to_string())));
let stack = push(stack, Value::String(global_string("salt".to_string())));
let stack = push(stack, Value::Int(0));
let stack = patch_seq_crypto_pbkdf2_sha256(stack);
let (_, success) = pop(stack);
assert_eq!(success, Value::Bool(false));
}
}
#[test]
fn test_encrypt_decrypt_with_derived_key() {
let password = "user-secret-password";
let salt = "unique-user-salt";
let iterations = 10000u32;
let key = derive_key_pbkdf2(password, salt, iterations);
let key_hex = hex::encode(key);
let plaintext = "sensitive data to protect";
let ciphertext = aes_gcm_encrypt(plaintext, &key_hex).unwrap();
let decrypted = aes_gcm_decrypt(&ciphertext, &key_hex).unwrap();
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_ed25519_sign_verify() {
let message = "Hello, World!";
let signing_key = SigningKey::generate(&mut OsRng);
let verifying_key = signing_key.verifying_key();
let private_hex = hex::encode(signing_key.to_bytes());
let public_hex = hex::encode(verifying_key.to_bytes());
let signature = ed25519_sign(message, &private_hex).unwrap();
assert_eq!(signature.len(), 128);
assert!(ed25519_verify(message, &signature, &public_hex));
}
#[test]
fn test_ed25519_wrong_message() {
let message = "Original message";
let wrong_message = "Wrong message";
let signing_key = SigningKey::generate(&mut OsRng);
let verifying_key = signing_key.verifying_key();
let private_hex = hex::encode(signing_key.to_bytes());
let public_hex = hex::encode(verifying_key.to_bytes());
let signature = ed25519_sign(message, &private_hex).unwrap();
assert!(!ed25519_verify(wrong_message, &signature, &public_hex));
}
#[test]
fn test_ed25519_wrong_key() {
let message = "Test message";
let signing_key1 = SigningKey::generate(&mut OsRng);
let signing_key2 = SigningKey::generate(&mut OsRng);
let private_hex = hex::encode(signing_key1.to_bytes());
let wrong_public_hex = hex::encode(signing_key2.verifying_key().to_bytes());
let signature = ed25519_sign(message, &private_hex).unwrap();
assert!(!ed25519_verify(message, &signature, &wrong_public_hex));
}
#[test]
fn test_ed25519_invalid_key_length() {
let message = "Test message";
let invalid_key = "tooshort";
assert!(ed25519_sign(message, invalid_key).is_none());
}
#[test]
fn test_ed25519_invalid_signature() {
let message = "Test message";
let signing_key = SigningKey::generate(&mut OsRng);
let public_hex = hex::encode(signing_key.verifying_key().to_bytes());
let invalid_signature = "0".repeat(128);
assert!(!ed25519_verify(message, &invalid_signature, &public_hex));
}
#[test]
fn test_ed25519_empty_message() {
let message = "";
let signing_key = SigningKey::generate(&mut OsRng);
let verifying_key = signing_key.verifying_key();
let private_hex = hex::encode(signing_key.to_bytes());
let public_hex = hex::encode(verifying_key.to_bytes());
let signature = ed25519_sign(message, &private_hex).unwrap();
assert!(ed25519_verify(message, &signature, &public_hex));
}
#[test]
fn test_ed25519_keypair_ffi() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = patch_seq_crypto_ed25519_keypair(stack);
let (stack, private_key) = pop(stack);
let (_, public_key) = pop(stack);
if let Value::String(pk) = public_key {
assert_eq!(pk.as_str().len(), 64);
} else {
panic!("Expected String for public key");
}
if let Value::String(sk) = private_key {
assert_eq!(sk.as_str().len(), 64);
} else {
panic!("Expected String for private key");
}
}
}
#[test]
fn test_ed25519_sign_ffi() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let signing_key = SigningKey::generate(&mut OsRng);
let private_hex = hex::encode(signing_key.to_bytes());
let stack = push(
stack,
Value::String(global_string("Test message".to_string())),
);
let stack = push(stack, Value::String(global_string(private_hex)));
let stack = patch_seq_crypto_ed25519_sign(stack);
let (stack, success) = pop(stack);
let (_, signature) = pop(stack);
assert_eq!(success, Value::Bool(true));
if let Value::String(sig) = signature {
assert_eq!(sig.as_str().len(), 128); } else {
panic!("Expected String for signature");
}
}
}
#[test]
fn test_ed25519_verify_ffi() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let signing_key = SigningKey::generate(&mut OsRng);
let verifying_key = signing_key.verifying_key();
let private_hex = hex::encode(signing_key.to_bytes());
let public_hex = hex::encode(verifying_key.to_bytes());
let message = "Verify this message";
let signature = ed25519_sign(message, &private_hex).unwrap();
let stack = push(stack, Value::String(global_string(message.to_string())));
let stack = push(stack, Value::String(global_string(signature)));
let stack = push(stack, Value::String(global_string(public_hex)));
let stack = patch_seq_crypto_ed25519_verify(stack);
let (_, valid) = pop(stack);
assert_eq!(valid, Value::Bool(true));
}
}
#[test]
fn test_random_int_basic() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(1));
let stack = push(stack, Value::Int(100));
let stack = patch_seq_random_int(stack);
let (_, value) = pop(stack);
match value {
Value::Int(n) => {
assert!((1..100).contains(&n), "Expected 1 <= {} < 100", n);
}
_ => panic!("Expected Int"),
}
}
}
#[test]
fn test_random_int_same_min_max() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(5));
let stack = push(stack, Value::Int(5));
let stack = patch_seq_random_int(stack);
let (_, value) = pop(stack);
match value {
Value::Int(n) => assert_eq!(n, 5),
_ => panic!("Expected Int"),
}
}
}
#[test]
fn test_random_int_inverted_range() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(10));
let stack = push(stack, Value::Int(5));
let stack = patch_seq_random_int(stack);
let (_, value) = pop(stack);
match value {
Value::Int(n) => assert_eq!(n, 10), _ => panic!("Expected Int"),
}
}
}
#[test]
fn test_random_int_small_range() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(0));
let stack = push(stack, Value::Int(2));
let stack = patch_seq_random_int(stack);
let (_, value) = pop(stack);
match value {
Value::Int(n) => assert!((0..2).contains(&n), "Expected 0 <= {} < 2", n),
_ => panic!("Expected Int"),
}
}
}
#[test]
fn test_random_int_negative_range() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(-10));
let stack = push(stack, Value::Int(10));
let stack = patch_seq_random_int(stack);
let (_, value) = pop(stack);
match value {
Value::Int(n) => assert!((-10..10).contains(&n), "Expected -10 <= {} < 10", n),
_ => panic!("Expected Int"),
}
}
}
#[test]
fn test_random_int_large_range() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(0));
let stack = push(stack, Value::Int(i64::MAX));
let stack = patch_seq_random_int(stack);
let (_, value) = pop(stack);
match value {
Value::Int(n) => assert!(n >= 0, "Expected {} >= 0", n),
_ => panic!("Expected Int"),
}
}
}
#[test]
fn test_random_int_extreme_range() {
unsafe {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(i64::MIN));
let stack = push(stack, Value::Int(i64::MAX));
let stack = patch_seq_random_int(stack);
let (_, value) = pop(stack);
match value {
Value::Int(_) => {} _ => panic!("Expected Int"),
}
}
}
#[test]
fn test_random_int_uniformity() {
let mut buckets = [0u32; 10];
let samples = 10000;
unsafe {
for _ in 0..samples {
let stack = crate::stack::alloc_test_stack();
let stack = push(stack, Value::Int(0));
let stack = push(stack, Value::Int(10));
let stack = patch_seq_random_int(stack);
let (_, value) = pop(stack);
if let Value::Int(n) = value {
buckets[n as usize] += 1;
}
}
}
let expected = samples as u32 / 10;
let tolerance = expected * 30 / 100;
for (i, &count) in buckets.iter().enumerate() {
assert!(
count >= expected - tolerance && count <= expected + tolerance,
"Bucket {} has {} samples, expected {} ± {} (uniformity test)",
i,
count,
expected,
tolerance
);
}
}