Compare commits

..

9 Commits

Author SHA1 Message Date
Maxime Van Hees
3e64a53a83 working example for mycelium
Some checks failed
Rhai Tests / Run Rhai Tests (pull_request) Has been cancelled
2025-05-13 14:10:32 +02:00
Maxime Van Hees
3225b3f029 corrected response mapping from API requests 2025-05-13 14:10:32 +02:00
Maxime Van Hees
3417e2c1ff fixed merge conflict 2025-05-13 14:10:10 +02:00
a4438d63e0 ... 2025-05-13 08:02:23 +03:00
393c4270d4 ... 2025-05-13 07:28:02 +03:00
495fe92321 Merge branch 'development_keypair_tests'
* development_keypair_tests:
  feat: Add comprehensive test suite for Keypair module
2025-05-13 06:51:30 +03:00
577d80b282 restore 2025-05-13 06:51:20 +03:00
3f8aecb786 tests & fixes in kvs & keypair 2025-05-13 06:45:04 +03:00
Mahmoud Emad
c7a5699798 feat: Add comprehensive test suite for Keypair module
- Added tests for keypair creation and operations.
- Added tests for key space management.
- Added tests for session management and error handling.
- Added tests for asymmetric encryption and decryption.
- Improved error handling and reporting in the module.
2025-05-12 15:44:14 +03:00
23 changed files with 1543 additions and 31 deletions

View File

@ -12,16 +12,16 @@ readme = "README.md"
[dependencies]
anyhow = "1.0.98"
base64 = "0.21.0" # Base64 encoding/decoding
base64 = "0.22.1" # Base64 encoding/decoding
cfg-if = "1.0"
chacha20poly1305 = "0.10.1" # ChaCha20Poly1305 AEAD cipher
clap = "2.33" # Command-line argument parsing
dirs = "5.0.1" # Directory paths
env_logger = "0.10.0" # Logger implementation
clap = "2.34.0" # Command-line argument parsing
dirs = "6.0.0" # Directory paths
env_logger = "0.11.8" # Logger implementation
ethers = { version = "2.0.7", features = ["legacy"] } # Ethereum library
glob = "0.3.1" # For file pattern matching
jsonrpsee = "0.25.1"
k256 = { version = "0.13.1", features = ["ecdsa"] } # Elliptic curve cryptography
k256 = { version = "0.13.4", features = ["ecdsa", "ecdh"] } # Elliptic curve cryptography
lazy_static = "1.4.0" # For lazy initialization of static variables
libc = "0.2"
log = "0.4" # Logging facade
@ -31,7 +31,7 @@ postgres-types = "0.2.5" # PostgreSQL type conversions
r2d2 = "0.8.10"
r2d2_postgres = "0.18.2"
rand = "0.8.5" # Random number generation
redis = "0.22.0" # Redis client
redis = "0.31.0" # Redis client
regex = "1.8.1" # For regex pattern matching
rhai = { version = "1.12.0", features = ["sync"] } # Embedded scripting language
serde = { version = "1.0", features = [
@ -41,7 +41,7 @@ serde_json = "1.0" # For JSON handling
sha2 = "0.10.7" # SHA-2 hash functions
tempfile = "3.5" # For temporary file operations
tera = "1.19.0" # Template engine for text rendering
thiserror = "1.0" # For error handling
thiserror = "2.0.12" # For error handling
tokio = "1.45.0"
tokio-postgres = "0.7.8" # Async PostgreSQL client
tokio-test = "0.4.4"
@ -52,17 +52,17 @@ urlencoding = "2.1.3"
# Optional features for specific OS functionality
[target.'cfg(unix)'.dependencies]
nix = "0.26" # Unix-specific functionality
nix = "0.30.1" # Unix-specific functionality
[target.'cfg(windows)'.dependencies]
windows = { version = "0.48", features = [
windows = { version = "0.61.1", features = [
"Win32_Foundation",
"Win32_System_Threading",
"Win32_Storage_FileSystem",
] }
[dev-dependencies]
mockall = "0.11.4" # For mocking in tests
mockall = "0.13.1" # For mocking in tests
tempfile = "3.5" # For tests that need temporary files/directories
tokio = { version = "1.28", features = ["full", "test-util"] } # For async testing

View File

@ -0,0 +1,108 @@
// 01_keypair_operations.rhai
// Tests for basic keypair operations in the Keypair module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
print("=== Testing Basic Keypair Operations ===");
// Test creating a new keypair
print("Testing keypair creation...");
let keypair_name = "test_keypair";
if create_key_space("test_space", "password") {
print("✓ Key space created successfully");
if create_keypair(keypair_name, "password") {
print("✓ Keypair created successfully");
// Test getting the public key
print("Testing public key retrieval...");
if select_keypair(keypair_name) {
let pub_key = keypair_pub_key();
assert_true(pub_key.len() > 0, "Public key should not be empty");
print(`✓ Public key retrieved: ${pub_key.len()} bytes`);
// Test signing a message
print("Testing message signing...");
let message = "This is a test message to sign";
let signature = keypair_sign(message);
assert_true(signature.len() > 0, "Signature should not be empty");
print(`✓ Message signed successfully: ${signature.len()} bytes`);
// Test verifying a signature
print("Testing signature verification...");
let is_valid = keypair_verify(message, signature);
assert_true(is_valid, "Signature should be valid");
print("✓ Signature verified successfully");
// Test verifying with just a public key
print("Testing verification with public key only...");
let is_valid_pub = verify_with_public_key(pub_key, message, signature);
assert_true(is_valid_pub, "Signature should be valid with public key only");
print("✓ Signature verified with public key only");
// Edge case: Empty message
print("Testing with empty message...");
let empty_message = "";
let empty_signature = keypair_sign(empty_message);
assert_true(empty_signature.len() > 0, "Signature for empty message should not be empty");
let is_valid_empty = keypair_verify(empty_message, empty_signature);
assert_true(is_valid_empty, "Empty message signature should be valid");
print("✓ Empty message signed and verified successfully");
// Edge case: Large message
print("Testing with large message...");
let large_message = "A" * 10000; // 10KB message
let large_signature = keypair_sign(large_message);
assert_true(large_signature.len() > 0, "Signature for large message should not be empty");
let is_valid_large = keypair_verify(large_message, large_signature);
assert_true(is_valid_large, "Large message signature should be valid");
print("✓ Large message signed and verified successfully");
// Error case: Invalid signature format
print("Testing with invalid signature format...");
let invalid_signature = [0, 1, 2, 3]; // Invalid signature bytes
let is_valid_invalid = false;
try {
is_valid_invalid = keypair_verify(message, invalid_signature);
} catch(err) {
print(`✓ Caught expected error for invalid signature: ${err}`);
}
assert_true(!is_valid_invalid, "Invalid signature should not verify");
// Error case: Tampered message
print("Testing with tampered message...");
let tampered_message = message + " (tampered)";
let is_valid_tampered = keypair_verify(tampered_message, signature);
assert_true(!is_valid_tampered, "Tampered message should not verify");
print("✓ Tampered message correctly failed verification");
// Error case: Malformed public key
print("Testing with malformed public key...");
let malformed_pub_key = [0, 1, 2, 3]; // Invalid public key bytes
let is_valid_malformed = false;
try {
is_valid_malformed = verify_with_public_key(malformed_pub_key, message, signature);
} catch(err) {
print(`✓ Caught expected error for malformed public key: ${err}`);
}
assert_true(!is_valid_malformed, "Malformed public key should not verify");
} else {
print("✗ Failed to select keypair");
throw "Failed to select keypair";
}
} else {
print("✗ Failed to create keypair");
throw "Failed to create keypair";
}
} else {
print("✗ Failed to create key space");
throw "Failed to create key space";
}
print("All keypair operations tests completed successfully!");

View File

@ -0,0 +1,162 @@
// 02_keyspace_operations.rhai
// Tests for key space operations in the Keypair module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
print("=== Testing Key Space Operations ===");
// Test creating a new key space
print("Testing key space creation...");
let space_name = "test_keyspace";
let password = "secure_password";
if create_key_space(space_name, password) {
print(`✓ Key space "${space_name}" created successfully`);
// Test adding keypairs to a key space
print("Testing adding keypairs to key space...");
let keypair1_name = "keypair1";
let keypair2_name = "keypair2";
if create_keypair(keypair1_name, password) {
print(`✓ Keypair "${keypair1_name}" created successfully`);
} else {
print(`✗ Failed to create keypair "${keypair1_name}"`);
throw `Failed to create keypair "${keypair1_name}"`;
}
if create_keypair(keypair2_name, password) {
print(`✓ Keypair "${keypair2_name}" created successfully`);
} else {
print(`✗ Failed to create keypair "${keypair2_name}"`);
throw `Failed to create keypair "${keypair2_name}"`;
}
// Test listing keypairs in a key space
print("Testing listing keypairs in key space...");
let keypairs = list_keypairs();
assert_true(keypairs.len() == 2, `Expected 2 keypairs, got ${keypairs.len()}`);
assert_true(keypairs.contains(keypair1_name), `Keypair list should contain "${keypair1_name}"`);
assert_true(keypairs.contains(keypair2_name), `Keypair list should contain "${keypair2_name}"`);
print(`✓ Listed keypairs successfully: ${keypairs}`);
// Test getting a keypair by name
print("Testing getting a keypair by name...");
if select_keypair(keypair1_name) {
print(`✓ Selected keypair "${keypair1_name}" successfully`);
let pub_key = keypair_pub_key();
assert_true(pub_key.len() > 0, "Public key should not be empty");
print(`✓ Retrieved public key for "${keypair1_name}": ${pub_key.len()} bytes`);
} else {
print(`✗ Failed to select keypair "${keypair1_name}"`);
throw `Failed to select keypair "${keypair1_name}"`;
}
// Edge case: Attempt to add a keypair with a duplicate name
print("Testing adding a keypair with a duplicate name...");
let duplicate_success = false;
try {
duplicate_success = create_keypair(keypair1_name, password);
} catch(err) {
print(`✓ Caught expected error for duplicate keypair: ${err}`);
}
assert_true(!duplicate_success, "Creating a duplicate keypair should fail");
// Edge case: Attempt to get a non-existent keypair
print("Testing getting a non-existent keypair...");
let nonexistent_success = false;
try {
nonexistent_success = select_keypair("nonexistent_keypair");
} catch(err) {
print(`✓ Caught expected error for non-existent keypair: ${err}`);
}
assert_true(!nonexistent_success, "Selecting a non-existent keypair should fail");
// Edge case: Test with special characters in keypair names
print("Testing with special characters in keypair name...");
let special_name = "special!@#$%^&*()_+";
if create_keypair(special_name, password) {
print(`✓ Created keypair with special characters: "${special_name}"`);
// Verify we can select and use it
if select_keypair(special_name) {
print(`✓ Selected keypair with special characters`);
let pub_key = keypair_pub_key();
assert_true(pub_key.len() > 0, "Public key should not be empty");
} else {
print(`✗ Failed to select keypair with special characters`);
throw `Failed to select keypair with special characters`;
}
} else {
print(`✗ Failed to create keypair with special characters`);
throw `Failed to create keypair with special characters`;
}
// Edge case: Test with very long keypair name
print("Testing with very long keypair name...");
let long_name = "a" * 100; // 100 character name
if create_keypair(long_name, password) {
print(`✓ Created keypair with long name (${long_name.len()} characters)`);
// Verify we can select and use it
if select_keypair(long_name) {
print(`✓ Selected keypair with long name`);
let pub_key = keypair_pub_key();
assert_true(pub_key.len() > 0, "Public key should not be empty");
} else {
print(`✗ Failed to select keypair with long name`);
throw `Failed to select keypair with long name`;
}
} else {
print(`✗ Failed to create keypair with long name`);
throw `Failed to create keypair with long name`;
}
// Edge case: Test with empty keypair name (should fail)
print("Testing with empty keypair name...");
let empty_name = "";
let empty_name_success = false;
try {
empty_name_success = create_keypair(empty_name, password);
} catch(err) {
print(`✓ Caught expected error for empty keypair name: ${err}`);
}
assert_true(!empty_name_success, "Creating a keypair with empty name should fail");
// Stress test: Add multiple keypairs
print("Stress testing: Adding multiple keypairs...");
let num_keypairs = 10; // Add 10 more keypairs
let stress_keypairs = [];
for i in 0..num_keypairs {
let name = `stress_keypair_${i}`;
stress_keypairs.push(name);
if create_keypair(name, password) {
print(`✓ Created stress test keypair ${i+1}/${num_keypairs}`);
} else {
print(`✗ Failed to create stress test keypair ${i+1}/${num_keypairs}`);
throw `Failed to create stress test keypair ${i+1}/${num_keypairs}`;
}
}
// Verify all keypairs were created
print("Verifying all stress test keypairs...");
let all_keypairs = list_keypairs();
for name in stress_keypairs {
assert_true(all_keypairs.contains(name), `Keypair list should contain "${name}"`);
}
print(`✓ All ${num_keypairs} stress test keypairs verified`);
} else {
print(`✗ Failed to create key space "${space_name}"`);
throw `Failed to create key space "${space_name}"`;
}
print("All key space operations tests completed successfully!");

View File

@ -0,0 +1,167 @@
// 03_session_management.rhai
// Tests for session management in the Keypair module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
print("=== Testing Session Management ===");
// Test creating a key space and setting it as current
print("Testing key space creation and activation...");
let space_name1 = "session_test_space1";
let space_name2 = "session_test_space2";
let password = "secure_password";
// Create first key space
if create_key_space(space_name1, password) {
print(`✓ Key space "${space_name1}" created successfully`);
// Test creating keypairs in the current space
print("Testing creating keypairs in current space...");
let keypair1_name = "session_keypair1";
if create_keypair(keypair1_name, password) {
print(`✓ Keypair "${keypair1_name}" created successfully in space "${space_name1}"`);
} else {
print(`✗ Failed to create keypair "${keypair1_name}" in space "${space_name1}"`);
throw `Failed to create keypair "${keypair1_name}" in space "${space_name1}"`;
}
// Test selecting a keypair
print("Testing selecting a keypair...");
if select_keypair(keypair1_name) {
print(`✓ Selected keypair "${keypair1_name}" successfully`);
} else {
print(`✗ Failed to select keypair "${keypair1_name}"`);
throw `Failed to select keypair "${keypair1_name}"`;
}
// Test getting the selected keypair
print("Testing getting the selected keypair...");
let pub_key = keypair_pub_key();
assert_true(pub_key.len() > 0, "Public key should not be empty");
print(`✓ Retrieved public key for selected keypair: ${pub_key.len()} bytes`);
// Create second key space
print("\nTesting creating and switching to a second key space...");
if create_key_space(space_name2, password) {
print(`✓ Key space "${space_name2}" created successfully`);
// Verify we're now in the second space
print("Verifying current space changed...");
let keypairs = list_keypairs();
assert_true(keypairs.len() == 0, `Expected 0 keypairs in new space, got ${keypairs.len()}`);
print("✓ Current space verified as the new space (empty keypair list)");
// Create a keypair in the second space
let keypair2_name = "session_keypair2";
if create_keypair(keypair2_name, password) {
print(`✓ Keypair "${keypair2_name}" created successfully in space "${space_name2}"`);
} else {
print(`✗ Failed to create keypair "${keypair2_name}" in space "${space_name2}"`);
throw `Failed to create keypair "${keypair2_name}" in space "${space_name2}"`;
}
// Switch back to first space
print("\nTesting switching back to first key space...");
if load_key_space(space_name1, password) {
print(`✓ Switched back to key space "${space_name1}" successfully`);
// Verify we're now in the first space
print("Verifying current space changed back...");
let keypairs = list_keypairs();
assert_true(keypairs.len() == 1, `Expected 1 keypair in original space, got ${keypairs.len()}`);
assert_true(keypairs.contains(keypair1_name), `Keypair list should contain "${keypair1_name}"`);
print("✓ Current space verified as the original space");
} else {
print(`✗ Failed to switch back to key space "${space_name1}"`);
throw `Failed to switch back to key space "${space_name1}"`;
}
} else {
print(`✗ Failed to create second key space "${space_name2}"`);
throw `Failed to create second key space "${space_name2}"`;
}
// Test clearing the session
print("\nTesting clearing the session...");
clear_session();
print("✓ Session cleared");
// Verify operations fail after clearing session
print("Verifying operations fail after clearing session...");
let list_success = false;
try {
list_keypairs();
list_success = true;
} catch(err) {
print(`✓ Caught expected error after clearing session: ${err}`);
}
assert_true(!list_success, "Listing keypairs should fail after clearing session");
// Error case: Attempt operations without an active key space
print("\nTesting operations without an active key space...");
// Attempt to create a keypair
let create_success = false;
try {
create_success = create_keypair("no_space_keypair", password);
} catch(err) {
print(`✓ Caught expected error for creating keypair without active space: ${err}`);
}
assert_true(!create_success, "Creating a keypair without active space should fail");
// Attempt to select a keypair
let select_success = false;
try {
select_success = select_keypair("no_space_keypair");
} catch(err) {
print(`✓ Caught expected error for selecting keypair without active space: ${err}`);
}
assert_true(!select_success, "Selecting a keypair without active space should fail");
// Reload a key space
print("\nTesting reloading a key space after clearing session...");
if load_key_space(space_name1, password) {
print(`✓ Reloaded key space "${space_name1}" successfully`);
// Verify the keypair is still there
let keypairs = list_keypairs();
assert_true(keypairs.contains(keypair1_name), `Keypair list should contain "${keypair1_name}"`);
print("✓ Keypair still exists in reloaded space");
} else {
print(`✗ Failed to reload key space "${space_name1}"`);
throw `Failed to reload key space "${space_name1}"`;
}
// Error case: Attempt to get selected keypair when none is selected
print("\nTesting getting selected keypair when none is selected...");
let get_selected_success = false;
try {
keypair_pub_key();
get_selected_success = true;
} catch(err) {
print(`✓ Caught expected error for getting selected keypair when none selected: ${err}`);
}
assert_true(!get_selected_success, "Getting selected keypair when none is selected should fail");
// Error case: Attempt to select non-existent keypair
print("\nTesting selecting a non-existent keypair...");
let select_nonexistent_success = false;
try {
select_nonexistent_success = select_keypair("nonexistent_keypair");
} catch(err) {
print(`✓ Caught expected error for selecting non-existent keypair: ${err}`);
}
assert_true(!select_nonexistent_success, "Selecting a non-existent keypair should fail");
} else {
print(`✗ Failed to create key space "${space_name1}"`);
throw `Failed to create key space "${space_name1}"`;
}
print("All session management tests completed successfully!");

View File

@ -0,0 +1,192 @@
// 04_encryption_decryption.rhai
// Tests for asymmetric encryption and decryption in the Keypair module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
print("=== Testing Asymmetric Encryption and Decryption ===");
// Test creating keypairs for sender and recipient
print("Setting up sender and recipient keypairs...");
let space_name = "encryption_test_space";
let password = "secure_password";
let sender_name = "sender_keypair";
let recipient_name = "recipient_keypair";
if create_key_space(space_name, password) {
print(`✓ Key space "${space_name}" created successfully`);
// Create sender keypair
if create_keypair(sender_name, password) {
print(`✓ Sender keypair "${sender_name}" created successfully`);
} else {
print(`✗ Failed to create sender keypair "${sender_name}"`);
throw `Failed to create sender keypair "${sender_name}"`;
}
// Create recipient keypair
if create_keypair(recipient_name, password) {
print(`✓ Recipient keypair "${recipient_name}" created successfully`);
} else {
print(`✗ Failed to create recipient keypair "${recipient_name}"`);
throw `Failed to create recipient keypair "${recipient_name}"`;
}
// Get recipient's public key
if select_keypair(recipient_name) {
print(`✓ Selected recipient keypair "${recipient_name}" successfully`);
let recipient_pub_key = keypair_pub_key();
assert_true(recipient_pub_key.len() > 0, "Recipient public key should not be empty");
print(`✓ Retrieved recipient public key: ${recipient_pub_key.len()} bytes`);
// Switch to sender keypair
if select_keypair(sender_name) {
print(`✓ Selected sender keypair "${sender_name}" successfully`);
// Test encrypting a message with recipient's public key
print("\nTesting encrypting a message...");
let message = "This is a secret message for the recipient";
let ciphertext = encrypt_asymmetric(recipient_pub_key, message);
assert_true(ciphertext.len() > 0, "Ciphertext should not be empty");
print(`✓ Message encrypted successfully: ${ciphertext.len()} bytes`);
// Switch back to recipient keypair to decrypt
if select_keypair(recipient_name) {
print(`✓ Switched back to recipient keypair "${recipient_name}" successfully`);
// Test decrypting the message
print("Testing decrypting the message...");
let decrypted = decrypt_asymmetric(ciphertext);
assert_true(decrypted == message, "Decrypted message should match original");
print(`✓ Message decrypted successfully: "${decrypted}"`);
// Edge case: Test with empty message
print("\nTesting with empty message...");
let empty_message = "";
let empty_ciphertext = encrypt_asymmetric(recipient_pub_key, empty_message);
assert_true(empty_ciphertext.len() > 0, "Ciphertext for empty message should not be empty");
let empty_decrypted = decrypt_asymmetric(empty_ciphertext);
assert_true(empty_decrypted == empty_message, "Decrypted empty message should be empty");
print("✓ Empty message encrypted and decrypted successfully");
// Edge case: Test with large message
print("\nTesting with large message...");
let large_message = "A" * 10000; // 10KB message
let large_ciphertext = encrypt_asymmetric(recipient_pub_key, large_message);
assert_true(large_ciphertext.len() > 0, "Ciphertext for large message should not be empty");
let large_decrypted = decrypt_asymmetric(large_ciphertext);
assert_true(large_decrypted == large_message, "Decrypted large message should match original");
print("✓ Large message encrypted and decrypted successfully");
// Error case: Attempt to decrypt with the wrong keypair
print("\nTesting decryption with wrong keypair...");
if select_keypair(sender_name) {
print(`✓ Switched to sender keypair "${sender_name}" successfully`);
let wrong_keypair_success = true;
try {
let wrong_decrypted = decrypt_asymmetric(ciphertext);
// If we get here, the decryption didn't fail as expected
assert_true(wrong_decrypted != message, "Decryption with wrong keypair should not match original message");
} catch(err) {
wrong_keypair_success = false;
print(`✓ Caught expected error for decryption with wrong keypair: ${err}`);
}
// Note: Some implementations might not throw an error but return garbage data
// So we don't assert on wrong_keypair_success
// Switch back to recipient for further tests
if select_keypair(recipient_name) {
print(`✓ Switched back to recipient keypair "${recipient_name}" successfully`);
} else {
print(`✗ Failed to switch back to recipient keypair "${recipient_name}"`);
throw `Failed to switch back to recipient keypair "${recipient_name}"`;
}
} else {
print(`✗ Failed to switch to sender keypair "${sender_name}"`);
throw `Failed to switch to sender keypair "${sender_name}"`;
}
// Error case: Test with malformed ciphertext
print("\nTesting with malformed ciphertext...");
let malformed_ciphertext = [0, 1, 2, 3]; // Invalid ciphertext bytes
let malformed_success = false;
try {
decrypt_asymmetric(malformed_ciphertext);
malformed_success = true;
} catch(err) {
print(`✓ Caught expected error for malformed ciphertext: ${err}`);
}
assert_true(!malformed_success, "Decrypting malformed ciphertext should fail");
// Error case: Test with invalid public key for encryption
print("\nTesting encryption with invalid public key...");
if select_keypair(sender_name) {
print(`✓ Switched to sender keypair "${sender_name}" successfully`);
let invalid_pub_key = [0, 1, 2, 3]; // Invalid public key bytes
let invalid_key_success = false;
try {
encrypt_asymmetric(invalid_pub_key, message);
invalid_key_success = true;
} catch(err) {
print(`✓ Caught expected error for invalid public key: ${err}`);
}
assert_true(!invalid_key_success, "Encrypting with invalid public key should fail");
} else {
print(`✗ Failed to switch to sender keypair "${sender_name}"`);
throw `Failed to switch to sender keypair "${sender_name}"`;
}
// Error case: Test with tampered ciphertext
print("\nTesting with tampered ciphertext...");
if select_keypair(recipient_name) {
print(`✓ Switched to recipient keypair "${recipient_name}" successfully`);
// Tamper with the ciphertext (change a byte in the middle)
let tampered_ciphertext = ciphertext.clone();
if tampered_ciphertext.len() > 100 {
tampered_ciphertext[100] = (tampered_ciphertext[100] + 1) % 256;
let tampered_success = false;
try {
let tampered_decrypted = decrypt_asymmetric(tampered_ciphertext);
tampered_success = tampered_decrypted == message;
} catch(err) {
print(`✓ Caught expected error for tampered ciphertext: ${err}`);
}
assert_true(!tampered_success, "Decrypting tampered ciphertext should fail or produce incorrect result");
} else {
print("Note: Ciphertext too short to test tampering");
}
} else {
print(`✗ Failed to switch to recipient keypair "${recipient_name}"`);
throw `Failed to switch to recipient keypair "${recipient_name}"`;
}
} else {
print(`✗ Failed to switch back to recipient keypair "${recipient_name}"`);
throw `Failed to switch back to recipient keypair "${recipient_name}"`;
}
} else {
print(`✗ Failed to select sender keypair "${sender_name}"`);
throw `Failed to select sender keypair "${sender_name}"`;
}
} else {
print(`✗ Failed to select recipient keypair "${recipient_name}"`);
throw `Failed to select recipient keypair "${recipient_name}"`;
}
} else {
print(`✗ Failed to create key space "${space_name}"`);
throw `Failed to create key space "${space_name}"`;
}
print("All asymmetric encryption and decryption tests completed successfully!");

View File

@ -0,0 +1,231 @@
// 05_error_handling.rhai
// Comprehensive error handling tests for the Keypair module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Helper function to test for expected errors
fn expect_error(fn_to_test, expected_error_substring) {
let error_caught = false;
let error_message = "";
try {
fn_to_test();
} catch(err) {
error_caught = true;
error_message = err.to_string();
}
if !error_caught {
print(`ASSERTION FAILED: Expected error containing "${expected_error_substring}" but no error was thrown`);
throw `Expected error containing "${expected_error_substring}" but no error was thrown`;
}
if !error_message.contains(expected_error_substring) {
print(`ASSERTION FAILED: Expected error containing "${expected_error_substring}" but got "${error_message}"`);
throw `Expected error containing "${expected_error_substring}" but got "${error_message}"`;
}
print(`✓ Caught expected error: ${error_message}`);
}
print("=== Testing Error Handling ===");
// Test all error types defined in CryptoError
// 1. Test InvalidKeyLength error
print("\n--- Testing InvalidKeyLength error ---");
expect_error(|| {
// Create a key space for testing
create_key_space("error_test_space", "password");
create_keypair("test_keypair", "password");
select_keypair("test_keypair");
// Try to verify with an invalid public key (wrong length)
verify_with_public_key([1, 2, 3], "test message", [1, 2, 3, 4]);
}, "InvalidKeyLength");
// 2. Test EncryptionFailed error
print("\n--- Testing EncryptionFailed error ---");
expect_error(|| {
// Create a key space for testing
create_key_space("error_test_space", "password");
create_keypair("test_keypair", "password");
select_keypair("test_keypair");
// Try to encrypt with an invalid public key
encrypt_asymmetric([1, 2, 3], "test message");
}, "EncryptionFailed");
// 3. Test DecryptionFailed error
print("\n--- Testing DecryptionFailed error ---");
expect_error(|| {
// Create a key space for testing
create_key_space("error_test_space", "password");
create_keypair("test_keypair", "password");
select_keypair("test_keypair");
// Try to decrypt invalid ciphertext
decrypt_asymmetric([1, 2, 3, 4]);
}, "DecryptionFailed");
// 4. Test SignatureFormatError error
print("\n--- Testing SignatureFormatError error ---");
expect_error(|| {
// Create a key space for testing
create_key_space("error_test_space", "password");
create_keypair("test_keypair", "password");
select_keypair("test_keypair");
// Try to verify with an invalid signature format
keypair_verify("test message", [1, 2, 3]);
}, "SignatureFormatError");
// 5. Test KeypairAlreadyExists error
print("\n--- Testing KeypairAlreadyExists error ---");
expect_error(|| {
// Create a key space for testing
create_key_space("error_test_space", "password");
create_keypair("duplicate_keypair", "password");
// Try to create a keypair with the same name
create_keypair("duplicate_keypair", "password");
}, "KeypairAlreadyExists");
// 6. Test KeypairNotFound error
print("\n--- Testing KeypairNotFound error ---");
expect_error(|| {
// Create a key space for testing
create_key_space("error_test_space", "password");
// Try to select a non-existent keypair
select_keypair("nonexistent_keypair");
}, "KeypairNotFound");
// 7. Test NoActiveSpace error
print("\n--- Testing NoActiveSpace error ---");
expect_error(|| {
// Clear the session
clear_session();
// Try to create a keypair without an active space
create_keypair("test_keypair", "password");
}, "NoActiveSpace");
// 8. Test NoKeypairSelected error
print("\n--- Testing NoKeypairSelected error ---");
expect_error(|| {
// Create a key space for testing
create_key_space("error_test_space", "password");
// Try to get the public key without selecting a keypair
keypair_pub_key();
}, "NoKeypairSelected");
// Test error propagation through the API
print("\n--- Testing error propagation ---");
let propagation_test = || {
// Create a key space for testing
create_key_space("error_test_space", "password");
// Create a keypair
create_keypair("test_keypair", "password");
// Clear the session to force an error
clear_session();
// This should fail with NoActiveSpace
select_keypair("test_keypair");
// This line should never be reached
print("ERROR: Code execution continued after error");
};
expect_error(propagation_test, "NoActiveSpace");
// Test recovery from errors
print("\n--- Testing recovery from errors ---");
let recovery_success = false;
try {
// Try an operation that will fail
clear_session();
list_keypairs(); // This should fail with NoActiveSpace
} catch(err) {
print(`✓ Caught expected error: ${err}`);
// Now recover by creating a new key space
if create_key_space("recovery_space", "password") {
// Create a keypair to verify recovery
if create_keypair("recovery_keypair", "password") {
let keypairs = list_keypairs();
if keypairs.contains("recovery_keypair") {
recovery_success = true;
print("✓ Successfully recovered from error");
}
}
}
}
assert_true(recovery_success, "Should be able to recover from errors");
// Test behavior when multiple errors occur in sequence
print("\n--- Testing sequential errors ---");
let sequential_errors_count = 0;
// First error: No active space
try {
clear_session();
list_keypairs();
} catch(err) {
sequential_errors_count += 1;
print(`✓ Caught first sequential error: ${err}`);
}
// Second error: Keypair not found
try {
create_key_space("sequential_space", "password");
select_keypair("nonexistent_keypair");
} catch(err) {
sequential_errors_count += 1;
print(`✓ Caught second sequential error: ${err}`);
}
// Third error: Keypair already exists
try {
create_keypair("sequential_keypair", "password");
create_keypair("sequential_keypair", "password");
} catch(err) {
sequential_errors_count += 1;
print(`✓ Caught third sequential error: ${err}`);
}
assert_true(sequential_errors_count == 3, `Expected 3 sequential errors, got ${sequential_errors_count}`);
// Test error handling with invalid parameters
print("\n--- Testing error handling with invalid parameters ---");
// Test with null/undefined parameters
try {
// Note: In Rhai, we can't directly pass null/undefined, but we can test with empty arrays
verify_with_public_key([], "message", []);
print("ERROR: verify_with_public_key with empty arrays didn't throw an error");
} catch(err) {
print(`✓ Caught expected error for invalid parameters: ${err}`);
}
// Test with wrong parameter types
try {
// Note: In Rhai, we can't easily pass wrong types, but we can test with strings instead of arrays
verify_with_public_key("not an array", "message", "not an array");
print("ERROR: verify_with_public_key with wrong types didn't throw an error");
} catch(err) {
print(`✓ Caught expected error for wrong parameter types: ${err}`);
}
print("All error handling tests completed successfully!");

View File

@ -0,0 +1,293 @@
// run_all_tests.rhai
// Runs all Keypair module tests
print("=== Running Keypair Module Tests ===");
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Run each test directly
let passed = 0;
let failed = 0;
let test_results = #{};
// Test 1: Keypair Operations
print("\n--- Running Keypair Operations Tests ---");
try {
// Clear any existing session
clear_session();
// Test creating a new keypair
print("Testing keypair creation...");
let keypair_name = "test_keypair";
if create_key_space("test_space", "password") {
print("✓ Key space created successfully");
if create_keypair(keypair_name, "password") {
print("✓ Keypair created successfully");
// Test getting the public key
print("Testing public key retrieval...");
if select_keypair(keypair_name) {
let pub_key = keypair_pub_key();
assert_true(pub_key.len() > 0, "Public key should not be empty");
print(`✓ Public key retrieved: ${pub_key.len()} bytes`);
// Test signing a message
print("Testing message signing...");
let message = "This is a test message to sign";
let signature = keypair_sign(message);
assert_true(signature.len() > 0, "Signature should not be empty");
print(`✓ Message signed successfully: ${signature.len()} bytes`);
// Test verifying a signature
print("Testing signature verification...");
let is_valid = keypair_verify(message, signature);
assert_true(is_valid, "Signature should be valid");
print("✓ Signature verified successfully");
}
}
}
print("--- Keypair Operations Tests completed successfully ---");
passed += 1;
test_results["01_keypair_operations"] = "PASSED";
} catch(err) {
print(`!!! Error in Keypair Operations Tests: ${err}`);
failed += 1;
test_results["01_keypair_operations"] = `FAILED: ${err}`;
}
// Test 2: Key Space Operations
print("\n--- Running Key Space Operations Tests ---");
try {
// Clear any existing session
clear_session();
// Test creating a new key space
print("Testing key space creation...");
let space_name = "test_keyspace";
let password = "secure_password";
if create_key_space(space_name, password) {
print(`✓ Key space "${space_name}" created successfully`);
// Test adding keypairs to a key space
print("Testing adding keypairs to key space...");
let keypair1_name = "keypair1";
let keypair2_name = "keypair2";
if create_keypair(keypair1_name, password) {
print(`✓ Keypair "${keypair1_name}" created successfully`);
}
if create_keypair(keypair2_name, password) {
print(`✓ Keypair "${keypair2_name}" created successfully`);
}
// Test listing keypairs in a key space
print("Testing listing keypairs in key space...");
let keypairs = list_keypairs();
assert_true(keypairs.len() == 2, `Expected 2 keypairs, got ${keypairs.len()}`);
assert_true(keypairs.contains(keypair1_name), `Keypair list should contain "${keypair1_name}"`);
assert_true(keypairs.contains(keypair2_name), `Keypair list should contain "${keypair2_name}"`);
print(`✓ Listed keypairs successfully: ${keypairs}`);
}
print("--- Key Space Operations Tests completed successfully ---");
passed += 1;
test_results["02_keyspace_operations"] = "PASSED";
} catch(err) {
print(`!!! Error in Key Space Operations Tests: ${err}`);
failed += 1;
test_results["02_keyspace_operations"] = `FAILED: ${err}`;
}
// Test 3: Session Management
print("\n--- Running Session Management Tests ---");
try {
// Clear any existing session
clear_session();
// Test creating a key space and setting it as current
print("Testing key space creation and activation...");
let space_name1 = "session_test_space1";
let space_name2 = "session_test_space2";
let password = "secure_password";
// Create first key space
if create_key_space(space_name1, password) {
print(`✓ Key space "${space_name1}" created successfully`);
// Test creating keypairs in the current space
print("Testing creating keypairs in current space...");
let keypair1_name = "session_keypair1";
if create_keypair(keypair1_name, password) {
print(`✓ Keypair "${keypair1_name}" created successfully in space "${space_name1}"`);
}
// Test selecting a keypair
print("Testing selecting a keypair...");
if select_keypair(keypair1_name) {
print(`✓ Selected keypair "${keypair1_name}" successfully`);
}
}
print("--- Session Management Tests completed successfully ---");
passed += 1;
test_results["03_session_management"] = "PASSED";
} catch(err) {
print(`!!! Error in Session Management Tests: ${err}`);
failed += 1;
test_results["03_session_management"] = `FAILED: ${err}`;
}
// Test 4: Encryption and Decryption
print("\n--- Running Encryption and Decryption Tests ---");
try {
// Clear any existing session
clear_session();
// Test creating keypairs for sender and recipient
print("Setting up sender and recipient keypairs...");
let space_name = "encryption_test_space";
let password = "secure_password";
let sender_name = "sender_keypair";
let recipient_name = "recipient_keypair";
if create_key_space(space_name, password) {
print(`✓ Key space "${space_name}" created successfully`);
// Create sender keypair
if create_keypair(sender_name, password) {
print(`✓ Sender keypair "${sender_name}" created successfully`);
}
// Create recipient keypair
if create_keypair(recipient_name, password) {
print(`✓ Recipient keypair "${recipient_name}" created successfully`);
}
// Get recipient's public key
if select_keypair(recipient_name) {
print(`✓ Selected recipient keypair "${recipient_name}" successfully`);
let recipient_pub_key = keypair_pub_key();
// Switch to sender keypair
if select_keypair(sender_name) {
print(`✓ Selected sender keypair "${sender_name}" successfully`);
// Test encrypting a message with recipient's public key
print("\nTesting encrypting a message...");
let message = "This is a secret message for the recipient";
let ciphertext = encrypt_asymmetric(recipient_pub_key, message);
// Switch back to recipient keypair to decrypt
if select_keypair(recipient_name) {
print(`✓ Switched back to recipient keypair "${recipient_name}" successfully`);
// Test decrypting the message
print("Testing decrypting the message...");
let decrypted = decrypt_asymmetric(ciphertext);
assert_true(decrypted == message, "Decrypted message should match original");
print(`✓ Message decrypted successfully: "${decrypted}"`);
}
}
}
}
print("--- Encryption and Decryption Tests completed successfully ---");
passed += 1;
test_results["04_encryption_decryption"] = "PASSED";
} catch(err) {
print(`!!! Error in Encryption and Decryption Tests: ${err}`);
failed += 1;
test_results["04_encryption_decryption"] = `FAILED: ${err}`;
}
// Test 5: Error Handling
print("\n--- Running Error Handling Tests ---");
try {
// Clear any existing session
clear_session();
// Test NoActiveSpace error
print("Testing NoActiveSpace error...");
let no_active_space_error_caught = false;
try {
// Try to create a keypair without an active space
create_keypair("test_keypair", "password");
} catch(err) {
no_active_space_error_caught = true;
print(`✓ Caught expected error: ${err}`);
}
assert_true(no_active_space_error_caught, "NoActiveSpace error should be caught");
// Create a key space for further tests
if create_key_space("error_test_space", "password") {
print(`✓ Key space created successfully`);
// Test KeypairNotFound error
print("Testing KeypairNotFound error...");
let keypair_not_found_error_caught = false;
try {
// Try to select a non-existent keypair
select_keypair("nonexistent_keypair");
} catch(err) {
keypair_not_found_error_caught = true;
print(`✓ Caught expected error: ${err}`);
}
assert_true(keypair_not_found_error_caught, "KeypairNotFound error should be caught");
// Test NoKeypairSelected error
print("Testing NoKeypairSelected error...");
let no_keypair_selected_error_caught = false;
try {
// Try to get the public key without selecting a keypair
keypair_pub_key();
} catch(err) {
no_keypair_selected_error_caught = true;
print(`✓ Caught expected error: ${err}`);
}
assert_true(no_keypair_selected_error_caught, "NoKeypairSelected error should be caught");
}
print("--- Error Handling Tests completed successfully ---");
passed += 1;
test_results["05_error_handling"] = "PASSED";
} catch(err) {
print(`!!! Error in Error Handling Tests: ${err}`);
failed += 1;
test_results["05_error_handling"] = `FAILED: ${err}`;
}
print("\n=== Test Summary ===");
print(`Passed: ${passed}`);
print(`Failed: ${failed}`);
print(`Total: ${passed + failed}`);
// Print detailed results
print("\n=== Detailed Test Results ===");
for key in test_results.keys() {
let result = test_results[key];
if result.starts_with("PASSED") {
print(`✓ ${key}: ${result}`);
} else {
print(`✗ ${key}: ${result}`);
}
}
if failed == 0 {
print("\n✅ All tests passed!");
} else {
print("\n❌ Some tests failed!");
}
// Return the number of failed tests (0 means success)
failed;

View File

@ -16,7 +16,7 @@ static ETH_WALLETS: Lazy<Mutex<HashMap<String, Vec<EthereumWallet>>>> = Lazy::ne
/// Creates an Ethereum wallet from the currently selected keypair for a specific network.
pub fn create_ethereum_wallet_for_network(network: NetworkConfig) -> Result<EthereumWallet, CryptoError> {
// Get the currently selected keypair
let keypair = crate::vault::keypair::get_selected_keypair()?;
let keypair = crate::vault::keyspace::get_selected_keypair()?;
// Create an Ethereum wallet from the keypair
let wallet = EthereumWallet::from_keypair(&keypair, network)?;
@ -77,7 +77,7 @@ pub fn clear_ethereum_wallets_for_network(network_name: &str) {
/// Creates an Ethereum wallet from a name and the currently selected keypair for a specific network.
pub fn create_ethereum_wallet_from_name_for_network(name: &str, network: NetworkConfig) -> Result<EthereumWallet, CryptoError> {
// Get the currently selected keypair
let keypair = crate::vault::keypair::get_selected_keypair()?;
let keypair = crate::vault::keyspace::get_selected_keypair()?;
// Create an Ethereum wallet from the name and keypair
let wallet = EthereumWallet::from_name_and_keypair(name, &keypair, network)?;

View File

@ -1,6 +1,7 @@
/// Implementation of keypair functionality.
use k256::ecdsa::{SigningKey, VerifyingKey, signature::{Signer, Verifier}, Signature};
use k256::ecdh::EphemeralSecret;
use rand::rngs::OsRng;
use serde::{Serialize, Deserialize};
use std::collections::HashMap;
@ -214,22 +215,24 @@ impl KeyPair {
let ephemeral_signing_key = SigningKey::random(&mut OsRng);
let ephemeral_public_key = VerifyingKey::from(&ephemeral_signing_key);
// Derive shared secret (this is a simplified ECDH)
// In a real implementation, we would use proper ECDH, but for this example:
let shared_point = recipient_key.to_encoded_point(false);
let shared_secret = {
// Derive shared secret using ECDH
let ephemeral_secret = EphemeralSecret::random(&mut OsRng);
let shared_secret = ephemeral_secret.diffie_hellman(&recipient_key.to_public_key());
// Derive encryption key from the shared secret (e.g., using HKDF or hashing)
// For simplicity, we'll hash the shared secret here
let encryption_key = {
let mut hasher = Sha256::default();
hasher.update(ephemeral_signing_key.to_bytes());
hasher.update(shared_point.as_bytes());
hasher.update(shared_secret.raw_secret_bytes());
hasher.finalize().to_vec()
};
// Encrypt the message using the derived key
let ciphertext = implementation::encrypt_with_key(&shared_secret, message)
let ciphertext = implementation::encrypt_with_key(&encryption_key, message)
.map_err(|e| CryptoError::EncryptionFailed(e.to_string()))?;
// Format: ephemeral_public_key || ciphertext
let mut result = ephemeral_public_key.to_sec1_bytes().to_vec();
let mut result = ephemeral_public_key.to_encoded_point(false).as_bytes().to_vec();
result.extend_from_slice(&ciphertext);
Ok(result)
@ -252,17 +255,19 @@ impl KeyPair {
let sender_key = VerifyingKey::from_sec1_bytes(ephemeral_public_key)
.map_err(|_| CryptoError::InvalidKeyLength)?;
// Derive shared secret (simplified ECDH)
let shared_point = sender_key.to_encoded_point(false);
let shared_secret = {
// Derive shared secret using ECDH
let recipient_secret = EphemeralSecret::random(&mut OsRng);
let shared_secret = recipient_secret.diffie_hellman(&sender_key.to_public_key());
// Derive decryption key from the shared secret (using the same method as encryption)
let decryption_key = {
let mut hasher = Sha256::default();
hasher.update(self.signing_key.to_bytes());
hasher.update(shared_point.as_bytes());
hasher.update(shared_secret.raw_secret_bytes());
hasher.finalize().to_vec()
};
// Decrypt the message using the derived key
implementation::decrypt_with_key(&shared_secret, actual_ciphertext)
implementation::decrypt_with_key(&decryption_key, actual_ciphertext)
.map_err(|e| CryptoError::DecryptionFailed(e.to_string()))
}
}

View File

@ -13,3 +13,6 @@ pub use session_manager::{
keypair_pub_key, derive_public_key, keypair_sign, keypair_verify,
verify_with_public_key, encrypt_asymmetric, decrypt_asymmetric
};
#[cfg(test)]
mod tests;

View File

@ -2,7 +2,7 @@ use once_cell::sync::Lazy;
use std::sync::Mutex;
use crate::vault::error::CryptoError;
use crate::vault::keypair::keypair_types::{KeyPair, KeySpace}; // Assuming KeyPair and KeySpace will be in keypair_types.rs
use crate::vault::keyspace::keypair_types::{KeyPair, KeySpace}; // Assuming KeyPair and KeySpace will be in keypair_types.rs
/// Session state for the current key space and selected keypair.
pub struct Session {

View File

@ -0,0 +1,36 @@
# Keyspace Module Specification
This document explains the purpose and functionality of the `keyspace` module within the Hero Vault.
## Purpose of the Module
The `keyspace` module provides a secure and organized way to manage cryptographic keypairs. It allows for the creation, storage, loading, and utilization of keypairs within designated containers called keyspaces. This module is essential for handling sensitive cryptographic material securely.
## What is a Keyspace?
A keyspace is a logical container designed to hold multiple cryptographic keypairs. It is represented by the `KeySpace` struct in the code. Keyspaces can be encrypted and persisted to disk, providing a secure method for storing collections of keypairs. Each keyspace is identified by a unique name.
## What is a Keypair?
A keypair, represented by the `KeyPair` struct, is a fundamental cryptographic element consisting of a mathematically linked pair of keys: a public key and a private key. In this module, ECDSA (Elliptic Curve Digital Signature Algorithm) keypairs are used.
* **Private Key:** This key is kept secret and is used for operations like signing data or decrypting messages intended for the keypair's owner.
* **Public Key:** This key can be shared openly and is used to verify signatures created by the corresponding private key or to encrypt messages that can only be decrypted by the private key.
## How Many Keypairs Per Space?
A keyspace can hold multiple keypairs. The `KeySpace` struct uses a `HashMap` to store keypairs, where each keypair is associated with a unique string name. There is no inherent, fixed limit on the number of keypairs a keyspace can contain, beyond the practical limitations of system memory.
## How Do We Load Them?
Keyspaces are loaded from persistent storage (disk) using the `KeySpace::load` function, which requires the keyspace name and a password for decryption. Once a `KeySpace` object is loaded into memory, it can be set as the currently active keyspace for the session using the `session_manager::set_current_space` function. Individual keypairs within the loaded keyspace are then accessed by their names using functions like `session_manager::select_keypair` and `session_manager::get_selected_keypair`.
## What Do They Do?
Keypairs within a keyspace are used to perform various cryptographic operations. The `KeyPair` struct provides methods for:
* **Digital Signatures:** Signing messages with the private key (`KeyPair::sign`) and verifying those signatures with the public key (`KeyPair::verify`).
* **Ethereum Address Derivation:** Generating an Ethereum address from the public key (`KeyPair::to_ethereum_address`).
* **Asymmetric Encryption/Decryption:** Encrypting data using a recipient's public key (`KeyPair::encrypt_asymmetric`) and decrypting data encrypted with the keypair's public key using the private key (`KeyPair::decrypt_asymmetric`).
The `session_manager` module provides functions that utilize the currently selected keypair to perform these operations within the context of the active session.

View File

@ -0,0 +1,86 @@
use crate::vault::keyspace::keypair_types::{KeyPair, KeySpace};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_keypair_creation() {
let keypair = KeyPair::new("test_keypair");
assert_eq!(keypair.name, "test_keypair");
// Basic check that keys are generated (they should have non-zero length)
assert!(!keypair.pub_key().is_empty());
}
#[test]
fn test_keypair_sign_and_verify() {
let keypair = KeyPair::new("test_keypair");
let message = b"This is a test message";
let signature = keypair.sign(message);
assert!(!signature.is_empty());
let is_valid = keypair.verify(message, &signature).expect("Verification failed");
assert!(is_valid);
// Test with a wrong message
let wrong_message = b"This is a different message";
let is_valid_wrong = keypair.verify(wrong_message, &signature).expect("Verification failed with wrong message");
assert!(!is_valid_wrong);
}
#[test]
fn test_verify_with_public_key() {
let keypair = KeyPair::new("test_keypair");
let message = b"Another test message";
let signature = keypair.sign(message);
let public_key = keypair.pub_key();
let is_valid = KeyPair::verify_with_public_key(&public_key, message, &signature).expect("Verification with public key failed");
assert!(is_valid);
// Test with a wrong public key
let wrong_keypair = KeyPair::new("wrong_keypair");
let wrong_public_key = wrong_keypair.pub_key();
let is_valid_wrong_key = KeyPair::verify_with_public_key(&wrong_public_key, message, &signature).expect("Verification with wrong public key failed");
assert!(!is_valid_wrong_key);
}
#[test]
fn test_asymmetric_encryption_decryption() {
// Sender's keypair
let sender_keypair = KeyPair::new("sender");
let sender_public_key = sender_keypair.pub_key();
// Recipient's keypair
let recipient_keypair = KeyPair::new("recipient");
let recipient_public_key = recipient_keypair.pub_key();
let message = b"This is a secret message";
// Sender encrypts for recipient
let ciphertext = sender_keypair.encrypt_asymmetric(&recipient_public_key, message).expect("Encryption failed");
assert!(!ciphertext.is_empty());
// Recipient decrypts
let decrypted_message = recipient_keypair.decrypt_asymmetric(&ciphertext).expect("Decryption failed");
assert_eq!(decrypted_message, message);
// Test decryption with wrong keypair
let wrong_keypair = KeyPair::new("wrong_recipient");
let result = wrong_keypair.decrypt_asymmetric(&ciphertext);
assert!(result.is_err());
}
#[test]
fn test_keyspace_add_keypair() {
let mut space = KeySpace::new("test_space");
space.add_keypair("keypair1").expect("Failed to add keypair1");
assert_eq!(space.keypairs.len(), 1);
assert!(space.keypairs.contains_key("keypair1"));
// Test adding a duplicate keypair
let result = space.add_keypair("keypair1");
assert!(result.is_err());
}
}

View File

@ -0,0 +1,3 @@
mod keypair_types_tests;
mod session_manager_tests;

View File

@ -0,0 +1,111 @@
use crate::vault::keyspace::session_manager::{
clear_session, create_keypair, create_space, get_current_space, get_selected_keypair,
list_keypairs, select_keypair, set_current_space, SESSION,
};
use crate::vault::keyspace::keypair_types::KeySpace;
// Helper function to clear the session before each test
fn setup_test() {
clear_session();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_and_get_space() {
setup_test();
create_space("test_space").expect("Failed to create space");
let space = get_current_space().expect("Failed to get current space");
assert_eq!(space.name, "test_space");
}
#[test]
fn test_set_current_space() {
setup_test();
let space = KeySpace::new("another_space");
set_current_space(space.clone()).expect("Failed to set current space");
let current_space = get_current_space().expect("Failed to get current space");
assert_eq!(current_space.name, "another_space");
}
#[test]
fn test_clear_session() {
setup_test();
create_space("test_space").expect("Failed to create space");
clear_session();
let result = get_current_space();
assert!(result.is_err());
}
#[test]
fn test_create_and_select_keypair() {
setup_test();
create_space("test_space").expect("Failed to create space");
create_keypair("test_keypair").expect("Failed to create keypair");
let keypair = get_selected_keypair().expect("Failed to get selected keypair");
assert_eq!(keypair.name, "test_keypair");
select_keypair("test_keypair").expect("Failed to select keypair");
let selected_keypair = get_selected_keypair().expect("Failed to get selected keypair after select");
assert_eq!(selected_keypair.name, "test_keypair");
}
#[test]
fn test_list_keypairs() {
setup_test();
create_space("test_space").expect("Failed to create space");
create_keypair("keypair1").expect("Failed to create keypair1");
create_keypair("keypair2").expect("Failed to create keypair2");
let keypairs = list_keypairs().expect("Failed to list keypairs");
assert_eq!(keypairs.len(), 2);
assert!(keypairs.contains(&"keypair1".to_string()));
assert!(keypairs.contains(&"keypair2".to_string()));
}
#[test]
fn test_create_keypair_no_active_space() {
setup_test();
let result = create_keypair("test_keypair");
assert!(result.is_err());
}
#[test]
fn test_select_keypair_no_active_space() {
setup_test();
let result = select_keypair("test_keypair");
assert!(result.is_err());
}
#[test]
fn test_select_nonexistent_keypair() {
setup_test();
create_space("test_space").expect("Failed to create space");
let result = select_keypair("nonexistent_keypair");
assert!(result.is_err());
}
#[test]
fn test_get_selected_keypair_no_active_space() {
setup_test();
let result = get_selected_keypair();
assert!(result.is_err());
}
#[test]
fn test_get_selected_keypair_no_keypair_selected() {
setup_test();
create_space("test_space").expect("Failed to create space");
let result = get_selected_keypair();
assert!(result.is_err());
}
#[test]
fn test_list_keypairs_no_active_space() {
setup_test();
let result = list_keypairs();
assert!(result.is_err());
}
}

View File

@ -165,3 +165,9 @@ let loaded_store = KvStore::load("my_store", "secure_password")?;
let api_key = loaded_store.get("api_key")?;
println!("API Key: {}", api_key.unwrap_or_default());
```
## to test
```bash
cargo test --lib vault::keypair
```

View File

@ -12,3 +12,6 @@ pub use store::{
create_store, open_store, delete_store,
list_stores, get_store_path
};
#[cfg(test)]
mod tests;

View File

@ -355,7 +355,7 @@ impl KvStore {
// Save to disk
self.save()?;
Ok(())
Ok(())
}
/// Gets the name of the store.

View File

@ -0,0 +1 @@
mod store_tests;

View File

@ -0,0 +1,105 @@
use crate::vault::kvs::store::{create_store, delete_store, open_store, KvStore};
use std::path::PathBuf;
// Helper function to generate a unique store name for each test
fn generate_test_store_name() -> String {
use rand::Rng;
let random_string: String = rand::thread_rng()
.sample_iter(&rand::distributions::Alphanumeric)
.take(10)
.map(char::from)
.collect();
format!("test_store_{}", random_string)
}
// Helper function to clean up test stores
fn cleanup_test_store(name: &str) {
let _ = delete_store(name);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_and_open_store() {
let store_name = generate_test_store_name();
let store = create_store(&store_name, false, None).expect("Failed to create store");
assert_eq!(store.name(), store_name);
assert!(!store.is_encrypted());
let opened_store = open_store(&store_name, None).expect("Failed to open store");
assert_eq!(opened_store.name(), store_name);
assert!(!opened_store.is_encrypted());
cleanup_test_store(&store_name);
}
#[test]
fn test_set_and_get_value() {
let store_name = generate_test_store_name();
let store = create_store(&store_name, false, None).expect("Failed to create store");
store.set("key1", &"value1").expect("Failed to set value");
let value: String = store.get("key1").expect("Failed to get value");
assert_eq!(value, "value1");
cleanup_test_store(&store_name);
}
#[test]
fn test_delete_value() {
let store_name = generate_test_store_name();
let store = create_store(&store_name, false, None).expect("Failed to create store");
store.set("key1", &"value1").expect("Failed to set value");
store.delete("key1").expect("Failed to delete value");
let result: Result<String, _> = store.get("key1");
assert!(result.is_err());
cleanup_test_store(&store_name);
}
#[test]
fn test_contains_key() {
let store_name = generate_test_store_name();
let store = create_store(&store_name, false, None).expect("Failed to create store");
store.set("key1", &"value1").expect("Failed to set value");
assert!(store.contains("key1").expect("Failed to check contains"));
assert!(!store.contains("key2").expect("Failed to check contains"));
cleanup_test_store(&store_name);
}
#[test]
fn test_list_keys() {
let store_name = generate_test_store_name();
let store = create_store(&store_name, false, None).expect("Failed to create store");
store.set("key1", &"value1").expect("Failed to set value");
store.set("key2", &"value2").expect("Failed to set value");
let keys = store.keys().expect("Failed to list keys");
assert_eq!(keys.len(), 2);
assert!(keys.contains(&"key1".to_string()));
assert!(keys.contains(&"key2".to_string()));
cleanup_test_store(&store_name);
}
#[test]
fn test_clear_store() {
let store_name = generate_test_store_name();
let store = create_store(&store_name, false, None).expect("Failed to create store");
store.set("key1", &"value1").expect("Failed to set value");
store.set("key2", &"value2").expect("Failed to set value");
store.clear().expect("Failed to clear store");
let keys = store.keys().expect("Failed to list keys after clear");
assert!(keys.is_empty());
cleanup_test_store(&store_name);
}
}

View File

@ -9,7 +9,7 @@
//! - Key-value store with encryption
pub mod error;
pub mod keypair;
pub mod keyspace;
pub mod symmetric;
pub mod ethereum;
pub mod kvs;
@ -17,4 +17,4 @@ pub mod kvs;
// Re-export modules
// Re-export common types for convenience
pub use error::CryptoError;
pub use keypair::{KeyPair, KeySpace};
pub use keyspace::{KeyPair, KeySpace};

View File

@ -7,7 +7,7 @@ use serde::{Serialize, Deserialize};
use sha2::{Sha256, Digest};
use crate::vault::error::CryptoError;
use crate::vault::keypair::KeySpace;
use crate::vault::keyspace::KeySpace;
/// The size of the nonce in bytes.
const NONCE_SIZE: usize = 12;