use criterion::{
black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput,
};
use cargocrypt::crypto::{
CryptoEngine, PerformanceProfile, EncryptionOptions, PlaintextSecret,
SecretMetadata, SecretType, DerivedKey, defaults,
};
fn generate_test_data(size: usize) -> Vec<u8> {
(0..size).map(|i| (i % 256) as u8).collect()
}
fn bench_key_derivation(c: &mut Criterion) {
let mut group = c.benchmark_group("key_derivation");
let password = "benchmark_password_with_sufficient_entropy_12345";
let salt = [42u8; defaults::SALT_LENGTH];
let profiles = [
("fast", PerformanceProfile::Fast),
("balanced", PerformanceProfile::Balanced),
("secure", PerformanceProfile::Secure),
("paranoid", PerformanceProfile::Paranoid),
];
for (name, profile) in profiles {
group.bench_with_input(
BenchmarkId::new("argon2", name),
&profile,
|b, &profile| {
b.iter(|| {
let engine = CryptoEngine::with_performance_profile(profile);
let options = EncryptionOptions::new()
.with_performance_profile(profile)
.with_salt(salt);
let plaintext = PlaintextSecret::from_string("test".to_string());
black_box(engine.encrypt(plaintext, password, options).unwrap());
})
},
);
}
group.finish();
}
fn bench_encryption_sizes(c: &mut Criterion) {
let mut group = c.benchmark_group("encryption_by_size");
let engine = CryptoEngine::new();
let password = "benchmark_password";
let sizes = [
("1KB", 1024),
("10KB", 10 * 1024),
("100KB", 100 * 1024),
("1MB", 1024 * 1024),
("10MB", 10 * 1024 * 1024),
];
for (name, size) in sizes {
let data = generate_test_data(size);
group.throughput(Throughput::Bytes(size as u64));
group.bench_with_input(
BenchmarkId::new("encrypt", name),
&data,
|b, data| {
b.iter(|| {
let options = EncryptionOptions::new();
black_box(engine.encrypt_bytes(data, password, options).unwrap());
})
},
);
let encrypted = engine.encrypt_bytes(&data, password, EncryptionOptions::new()).unwrap();
group.bench_with_input(
BenchmarkId::new("decrypt", name),
&encrypted,
|b, encrypted| {
b.iter(|| {
black_box(engine.decrypt(encrypted, password).unwrap());
})
},
);
}
group.finish();
}
fn bench_direct_crypto(c: &mut Criterion) {
let mut group = c.benchmark_group("direct_crypto");
let engine = CryptoEngine::new();
let key = CryptoEngine::generate_key().unwrap();
let nonce = CryptoEngine::generate_nonce().unwrap();
let sizes = [
("1KB", 1024),
("10KB", 10 * 1024),
("100KB", 100 * 1024),
("1MB", 1024 * 1024),
];
for (name, size) in sizes {
let data = generate_test_data(size);
group.throughput(Throughput::Bytes(size as u64));
group.bench_with_input(
BenchmarkId::new("direct_encrypt", name),
&data,
|b, data| {
b.iter(|| {
black_box(engine.encrypt_direct(data, &key, &nonce).unwrap());
})
},
);
let ciphertext = engine.encrypt_direct(&data, &key, &nonce).unwrap();
group.bench_with_input(
BenchmarkId::new("direct_decrypt", name),
&ciphertext,
|b, ciphertext| {
b.iter(|| {
black_box(engine.decrypt_direct(ciphertext, &key, &nonce).unwrap());
})
},
);
}
group.finish();
}
fn bench_batch_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("batch_operations");
let engine = CryptoEngine::new();
let password = "batch_password";
let batch_sizes = [1, 10, 50, 100, 500];
for &count in &batch_sizes {
let secrets: Vec<(String, String)> = (0..count)
.map(|i| (format!("secret_{}", i), format!("secret_data_{}_with_some_content", i)))
.collect();
group.bench_with_input(
BenchmarkId::new("encrypt_batch", count),
&secrets,
|b, secrets| {
b.iter(|| {
let options = EncryptionOptions::new();
black_box(engine.encrypt_batch(secrets.clone(), password, options));
})
},
);
}
group.finish();
}
fn bench_password_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("password_operations");
let engine = CryptoEngine::new();
let plaintext = "Test secret data for password operations";
let password = "original_password";
let new_password = "new_password";
let encrypted = engine.encrypt_string(plaintext, password, EncryptionOptions::new()).unwrap();
group.bench_function("verify_correct_password", |b| {
b.iter(|| {
black_box(engine.verify_password(&encrypted, password));
})
});
group.bench_function("verify_wrong_password", |b| {
b.iter(|| {
black_box(engine.verify_password(&encrypted, "wrong_password"));
})
});
group.bench_function("change_password", |b| {
b.iter(|| {
black_box(engine.change_password(&encrypted, password, new_password).unwrap());
})
});
group.finish();
}
fn bench_serialization(c: &mut Criterion) {
let mut group = c.benchmark_group("serialization");
let engine = CryptoEngine::new();
let plaintext = "Test data for serialization benchmarks";
let password = "serialization_password";
let metadata = SecretMetadata::new()
.with_description("Benchmark secret")
.with_type(SecretType::ApiKey);
let options = EncryptionOptions::new().with_metadata(metadata);
let encrypted = engine.encrypt_string(plaintext, password, options).unwrap();
group.bench_function("to_json", |b| {
b.iter(|| {
black_box(encrypted.to_json().unwrap());
})
});
let json = encrypted.to_json().unwrap();
group.bench_function("from_json", |b| {
b.iter(|| {
black_box(cargocrypt::crypto::EncryptedSecret::from_json(&json).unwrap());
})
});
group.bench_function("to_bytes", |b| {
b.iter(|| {
black_box(encrypted.to_bytes().unwrap());
})
});
let bytes = encrypted.to_bytes().unwrap();
group.bench_function("from_bytes", |b| {
b.iter(|| {
black_box(cargocrypt::crypto::EncryptedSecret::from_bytes(&bytes).unwrap());
})
});
group.finish();
}
fn bench_memory_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("memory_operations");
let engine = CryptoEngine::new();
let password = "memory_test_password";
let large_data = generate_test_data(1024 * 1024);
group.bench_function("large_data_encrypt", |b| {
b.iter(|| {
let options = EncryptionOptions::new();
black_box(engine.encrypt_bytes(&large_data, password, options).unwrap());
})
});
let encrypted_large = engine.encrypt_bytes(&large_data, password, EncryptionOptions::new()).unwrap();
group.bench_function("large_data_decrypt", |b| {
b.iter(|| {
black_box(engine.decrypt(&encrypted_large, password).unwrap());
})
});
group.bench_function("many_small_encryptions", |b| {
b.iter(|| {
for i in 0..100 {
let data = format!("small_secret_{}", i);
let options = EncryptionOptions::new();
black_box(engine.encrypt_string(&data, password, options).unwrap());
}
})
});
group.finish();
}
fn bench_concurrent_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("concurrent_operations");
let engine = CryptoEngine::new();
let password = "concurrent_password";
let data = "Concurrent test data";
let encrypted = engine.encrypt_string(data, password, EncryptionOptions::new()).unwrap();
group.bench_function("concurrent_encryptions", |b| {
b.iter(|| {
use std::thread;
let handles: Vec<_> = (0..4).map(|_| {
let engine = engine.clone();
let data = data.to_string();
let password = password.to_string();
thread::spawn(move || {
let options = EncryptionOptions::new();
engine.encrypt_string(&data, &password, options).unwrap()
})
}).collect();
for handle in handles {
black_box(handle.join().unwrap());
}
})
});
group.bench_function("concurrent_decryptions", |b| {
b.iter(|| {
use std::thread;
let handles: Vec<_> = (0..4).map(|_| {
let engine = engine.clone();
let encrypted = encrypted.clone();
let password = password.to_string();
thread::spawn(move || {
engine.decrypt_to_string(&encrypted, &password).unwrap()
})
}).collect();
for handle in handles {
black_box(handle.join().unwrap());
}
})
});
group.finish();
}
fn bench_performance_targets(c: &mut Criterion) {
let mut group = c.benchmark_group("performance_targets");
group.significance_level(0.1).sample_size(100);
let engine = CryptoEngine::new();
let password = "target_password";
let test_data = "Performance target test data";
group.bench_function("target_encrypt_small", |b| {
b.iter(|| {
let options = EncryptionOptions::new();
black_box(engine.encrypt_string(test_data, password, options).unwrap());
})
});
let encrypted = engine.encrypt_string(test_data, password, EncryptionOptions::new()).unwrap();
group.bench_function("target_decrypt_small", |b| {
b.iter(|| {
black_box(engine.decrypt_to_string(&encrypted, password).unwrap());
})
});
let large_data = generate_test_data(10 * 1024 * 1024); group.throughput(Throughput::Bytes(large_data.len() as u64));
group.bench_function("target_encrypt_large", |b| {
b.iter(|| {
let options = EncryptionOptions::new();
black_box(engine.encrypt_bytes(&large_data, password, options).unwrap());
})
});
let encrypted_large = engine.encrypt_bytes(&large_data, password, EncryptionOptions::new()).unwrap();
group.bench_function("target_decrypt_large", |b| {
b.iter(|| {
black_box(engine.decrypt(&encrypted_large, password).unwrap());
})
});
group.finish();
}
criterion_group!(
benches,
bench_key_derivation,
bench_encryption_sizes,
bench_direct_crypto,
bench_batch_operations,
bench_password_operations,
bench_serialization,
bench_memory_operations,
bench_concurrent_operations,
bench_performance_targets,
);
criterion_main!(benches);