MOD: cleanup move tests out of reg classes

This commit is contained in:
JohnE 2026-03-11 21:34:31 -07:00
parent cc72bb8919
commit 3ea964d3d9
6 changed files with 214 additions and 200 deletions

10
.vscode/settings.json vendored
View File

@ -1,4 +1,8 @@
{
"[rust]": {
"editor.formatOnSave": false,
"editor.formatOnPaste": false
},
"cmake.configureOnOpen": false,
"dart.analysisExcludedFolders": [
"flutter_src",
@ -15,6 +19,10 @@
"AllBlockComments"
],
"chat.tools.terminal.autoApprove": {
"cargo search": true
"cargo search": true,
"/^source \"\\$HOME/\\.cargo/env\" && cd /Volumes/LUM/source/letusmsg_proj/app/lum_ccc_rust && python3 -c \"\n# Self-test AES-GCM vector\nkey = 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308'\nnonce = 'cafebabefacedbaddecaf888'\naad = ''\npt = 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255'\nct_tag = '522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad'\n\nprint\\('Self-test AES-GCM:'\\)\nprint\\(f' PT bytes: \\{len\\(pt\\)//2\\}'\\)\nprint\\(f' CT_TAG bytes: \\{len\\(ct_tag\\)//2\\}'\\)\nprint\\(f' Expected \\(PT \\+ 16 tag\\): \\{len\\(pt\\)//2 \\+ 16\\}'\\)\nprint\\(f' ct_tag IS ciphertext-only \\(no tag\\): \\{len\\(ct_tag\\)//2 == len\\(pt\\)//2\\}'\\)\nprint\\(\\)\n\n# Conformance AES-GCM vector \\(different: has AAD, shorter PT\\)\npt2 = 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39'\nct_tag2 = '522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f66276fc6ece0f4e1768cddf8853bb2d551b'\nprint\\('Conformance AES-GCM TC16:'\\)\nprint\\(f' PT bytes: \\{len\\(pt2\\)//2\\}'\\)\nprint\\(f' CT_TAG bytes: \\{len\\(ct_tag2\\)//2\\}'\\)\nprint\\(f' CT_TAG == PT \\+ 16: \\{len\\(ct_tag2\\)//2 == len\\(pt2\\)//2 \\+ 16\\}'\\)\nprint\\(\\)\n\n# Self-test ChaCha vector\npt3 = '4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f6620273939'\nct_tag3 = 'd31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116'\nprint\\('Self-test ChaCha:'\\)\nprint\\(f' PT bytes: \\{len\\(pt3\\)//2\\}'\\)\nprint\\(f' CT_TAG bytes: \\{len\\(ct_tag3\\)//2\\}'\\)\nprint\\(f' CT_TAG == PT \\+ 16: \\{len\\(ct_tag3\\)//2 == len\\(pt3\\)//2 \\+ 16\\}'\\)\nprint\\(f' Ratio: CT_TAG is \\{len\\(ct_tag3\\)//2 - len\\(pt3\\)//2\\} bytes longer than PT'\\)\n\"\n$/": {
"approve": true,
"matchCommandLine": true
}
}
}

View File

@ -94,182 +94,6 @@ impl ProviderRegistry {
}
}
// ──────────────────────────────────────────────────────────────────────────────
// Tests
// ──────────────────────────────────────────────────────────────────────────────
#[cfg(test)]
mod tests {
//! Registry unit tests use a stub provider to avoid any native dependency.
use super::*;
use crate::{
algorithms::{AeadAlgorithm, HashAlgorithm, KdfAlgorithm, MacAlgorithm},
capabilities::ProviderCapabilities,
error::CryptoError,
provider::{AeadProvider, CryptoProvider, HashProvider, KdfProvider, MacProvider},
types::{AlgoBenchResult, AlgoTestResult, BenchmarkReport, SelfTestReport},
};
use zeroize::Zeroizing;
// ── Stub provider ──────────────────────────────────────────────────────────
struct StubProvider;
impl AeadProvider for StubProvider {
fn encrypt_aead(
&self,
_a: AeadAlgorithm,
_k: &[u8],
_n: &[u8],
pt: &[u8],
_aad: &[u8],
) -> Result<Vec<u8>, CryptoError> {
Ok(pt.to_vec())
}
fn decrypt_aead(
&self,
_a: AeadAlgorithm,
_k: &[u8],
_n: &[u8],
ct: &[u8],
_aad: &[u8],
) -> Result<Vec<u8>, CryptoError> {
Ok(ct.to_vec())
}
}
impl KdfProvider for StubProvider {
fn derive_key(
&self,
_a: KdfAlgorithm,
_ikm: &[u8],
_salt: &[u8],
_info: &[u8],
length: usize,
) -> Result<Zeroizing<Vec<u8>>, CryptoError> {
Ok(Zeroizing::new(vec![0u8; length]))
}
}
impl MacProvider for StubProvider {
fn compute_mac(
&self,
_a: MacAlgorithm,
_k: &[u8],
_data: &[u8],
) -> Result<Vec<u8>, CryptoError> {
Ok(vec![0u8; 32])
}
fn verify_mac(
&self,
_a: MacAlgorithm,
_k: &[u8],
_data: &[u8],
_mac: &[u8],
) -> Result<bool, CryptoError> {
Ok(true)
}
}
impl HashProvider for StubProvider {
fn hash(&self, _a: HashAlgorithm, data: &[u8]) -> Result<Vec<u8>, CryptoError> {
Ok(data.to_vec())
}
}
impl CryptoProvider for StubProvider {
fn provider_name(&self) -> &'static str {
"stub"
}
fn capabilities(&self) -> ProviderCapabilities {
ProviderCapabilities::empty("stub")
}
fn self_test(&self) -> SelfTestReport {
SelfTestReport::finalise(
"stub",
vec![AlgoTestResult {
algo_id: 12,
algo_name: "stub".into(),
passed: true,
error_message: None,
}],
)
}
fn benchmark(&self) -> BenchmarkReport {
BenchmarkReport {
provider_name: "stub".into(),
results: vec![AlgoBenchResult {
algo_id: 12,
algo_name: "stub".into(),
throughput_mbps: 999.0,
efficiency_score: 100,
}],
}
}
}
// ── Tests ──────────────────────────────────────────────────────────────────
fn fresh_registry() -> ProviderRegistry {
ProviderRegistry {
inner: Mutex::new(HashMap::new()),
}
}
#[test]
fn register_and_get() {
let reg = fresh_registry();
assert!(reg.get("stub").is_none());
reg.register("stub", Box::new(StubProvider));
assert!(reg.get("stub").is_some());
}
#[test]
fn list_providers() {
let reg = fresh_registry();
assert!(reg.list().is_empty());
reg.register("stub", Box::new(StubProvider));
let names = reg.list();
assert_eq!(names.len(), 1);
assert_eq!(names[0], "stub");
}
#[test]
fn contains_and_unregister() {
let reg = fresh_registry();
reg.register("stub", Box::new(StubProvider));
assert!(reg.contains("stub"));
reg.unregister("stub");
assert!(!reg.contains("stub"));
}
#[test]
fn register_replaces_existing() {
let reg = fresh_registry();
reg.register("stub", Box::new(StubProvider));
reg.register("stub", Box::new(StubProvider)); // replace
assert_eq!(reg.list().len(), 1);
}
#[test]
fn stub_provider_roundtrip() {
let reg = fresh_registry();
reg.register("stub", Box::new(StubProvider));
let provider = reg.get("stub").unwrap();
let plaintext = b"hello world";
let ct = provider
.encrypt_aead(
AeadAlgorithm::AesGcm256,
&[0u8; 32],
&[0u8; 12],
plaintext,
b"",
)
.unwrap();
let pt = provider
.decrypt_aead(AeadAlgorithm::AesGcm256, &[0u8; 32], &[0u8; 12], &ct, b"")
.unwrap();
assert_eq!(pt, plaintext);
}
}
#[path = "registry_tests.rs"]
mod tests;

View File

@ -0,0 +1,172 @@
//! Registry unit tests — use a stub provider to avoid any native dependency.
use super::*;
use crate::{
algorithms::{AeadAlgorithm, HashAlgorithm, KdfAlgorithm, MacAlgorithm},
capabilities::ProviderCapabilities,
error::CryptoError,
provider::{AeadProvider, CryptoProvider, HashProvider, KdfProvider, MacProvider},
types::{AlgoBenchResult, AlgoTestResult, BenchmarkReport, SelfTestReport},
};
use zeroize::Zeroizing;
// ── Stub provider ──────────────────────────────────────────────────────────
struct StubProvider;
impl AeadProvider for StubProvider {
fn encrypt_aead(
&self,
_a: AeadAlgorithm,
_k: &[u8],
_n: &[u8],
pt: &[u8],
_aad: &[u8],
) -> Result<Vec<u8>, CryptoError> {
Ok(pt.to_vec())
}
fn decrypt_aead(
&self,
_a: AeadAlgorithm,
_k: &[u8],
_n: &[u8],
ct: &[u8],
_aad: &[u8],
) -> Result<Vec<u8>, CryptoError> {
Ok(ct.to_vec())
}
}
impl KdfProvider for StubProvider {
fn derive_key(
&self,
_a: KdfAlgorithm,
_ikm: &[u8],
_salt: &[u8],
_info: &[u8],
length: usize,
) -> Result<Zeroizing<Vec<u8>>, CryptoError> {
Ok(Zeroizing::new(vec![0u8; length]))
}
}
impl MacProvider for StubProvider {
fn compute_mac(
&self,
_a: MacAlgorithm,
_k: &[u8],
_data: &[u8],
) -> Result<Vec<u8>, CryptoError> {
Ok(vec![0u8; 32])
}
fn verify_mac(
&self,
_a: MacAlgorithm,
_k: &[u8],
_data: &[u8],
_mac: &[u8],
) -> Result<bool, CryptoError> {
Ok(true)
}
}
impl HashProvider for StubProvider {
fn hash(&self, _a: HashAlgorithm, data: &[u8]) -> Result<Vec<u8>, CryptoError> {
Ok(data.to_vec())
}
}
impl CryptoProvider for StubProvider {
fn provider_name(&self) -> &'static str {
"stub"
}
fn capabilities(&self) -> ProviderCapabilities {
ProviderCapabilities::empty("stub")
}
fn self_test(&self) -> SelfTestReport {
SelfTestReport::finalise(
"stub",
vec![AlgoTestResult {
algo_id: 12,
algo_name: "stub".into(),
passed: true,
error_message: None,
}],
)
}
fn benchmark(&self) -> BenchmarkReport {
BenchmarkReport {
provider_name: "stub".into(),
results: vec![AlgoBenchResult {
algo_id: 12,
algo_name: "stub".into(),
throughput_mbps: 999.0,
efficiency_score: 100,
}],
}
}
}
// ── Tests ──────────────────────────────────────────────────────────────────
fn fresh_registry() -> ProviderRegistry {
ProviderRegistry {
inner: Mutex::new(HashMap::new()),
}
}
#[test]
fn register_and_get() {
let reg = fresh_registry();
assert!(reg.get("stub").is_none());
reg.register("stub", Box::new(StubProvider));
assert!(reg.get("stub").is_some());
}
#[test]
fn list_providers() {
let reg = fresh_registry();
assert!(reg.list().is_empty());
reg.register("stub", Box::new(StubProvider));
let names = reg.list();
assert_eq!(names.len(), 1);
assert_eq!(names[0], "stub");
}
#[test]
fn contains_and_unregister() {
let reg = fresh_registry();
reg.register("stub", Box::new(StubProvider));
assert!(reg.contains("stub"));
reg.unregister("stub");
assert!(!reg.contains("stub"));
}
#[test]
fn register_replaces_existing() {
let reg = fresh_registry();
reg.register("stub", Box::new(StubProvider));
reg.register("stub", Box::new(StubProvider)); // replace
assert_eq!(reg.list().len(), 1);
}
#[test]
fn stub_provider_roundtrip() {
let reg = fresh_registry();
reg.register("stub", Box::new(StubProvider));
let provider = reg.get("stub").unwrap();
let plaintext = b"hello world";
let ct = provider
.encrypt_aead(
AeadAlgorithm::AesGcm256,
&[0u8; 32],
&[0u8; 12],
plaintext,
b"",
)
.unwrap();
let pt = provider
.decrypt_aead(AeadAlgorithm::AesGcm256, &[0u8; 32], &[0u8; 12], &ct, b"")
.unwrap();
assert_eq!(pt, plaintext);
}

View File

@ -58,7 +58,11 @@ pub fn probe_capabilities(benchmarks: Option<&BenchmarkReport>) -> ProviderCapab
caps = caps.with_aead(AeadAlgorithm::Ascon128a, AlgorithmCapability::unavailable());
// ── KDF ──────────────────────────────────────────────────────────────────
for algo in [KdfAlgorithm::Sha256, KdfAlgorithm::Sha384, KdfAlgorithm::Sha512] {
for algo in [
KdfAlgorithm::Sha256,
KdfAlgorithm::Sha384,
KdfAlgorithm::Sha512,
] {
let available = crate::kdf::derive_key(algo, b"key", b"salt", b"info", 32).is_ok();
caps = caps.with_kdf(
algo,
@ -94,7 +98,11 @@ pub fn probe_capabilities(benchmarks: Option<&BenchmarkReport>) -> ProviderCapab
caps = caps.with_kdf(KdfAlgorithm::Kmac256, AlgorithmCapability::unavailable());
// ── MAC ──────────────────────────────────────────────────────────────────
for algo in [MacAlgorithm::HmacSha256, MacAlgorithm::HmacSha384, MacAlgorithm::HmacSha512] {
for algo in [
MacAlgorithm::HmacSha256,
MacAlgorithm::HmacSha384,
MacAlgorithm::HmacSha512,
] {
let available = crate::mac::compute_mac(algo, b"key", b"data").is_ok();
caps = caps.with_mac(
algo,

View File

@ -23,7 +23,7 @@ pub fn compute_mac(algo: MacAlgorithm, key: &[u8], data: &[u8]) -> Result<Vec<u8
MacAlgorithm::HmacSha384 => hmac(WC_HASH_TYPE_SHA384, key, data, 48),
MacAlgorithm::HmacSha512 => hmac(WC_HASH_TYPE_SHA512, key, data, 64),
MacAlgorithm::Blake2bMac => blake2b_mac(key, data),
MacAlgorithm::Poly1305 => Err(CryptoError::UnsupportedAlgorithm(
MacAlgorithm::Poly1305 => Err(CryptoError::UnsupportedAlgorithm(
"Poly1305 standalone MAC is not exposed in this Phase".into(),
)),
}
@ -197,21 +197,5 @@ fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
}
#[cfg(test)]
mod tests {
use super::constant_time_eq;
#[test]
fn ct_eq_same() {
assert!(constant_time_eq(b"hello", b"hello"));
}
#[test]
fn ct_eq_different() {
assert!(!constant_time_eq(b"hello", b"Hello"));
}
#[test]
fn ct_eq_different_lengths() {
assert!(!constant_time_eq(b"hi", b"hello"));
}
}
#[path = "mac_tests.rs"]
mod tests;

View File

@ -0,0 +1,18 @@
//! Unit tests for constant-time comparison in the MAC module.
use super::constant_time_eq;
#[test]
fn ct_eq_same() {
assert!(constant_time_eq(b"hello", b"hello"));
}
#[test]
fn ct_eq_different() {
assert!(!constant_time_eq(b"hello", b"Hello"));
}
#[test]
fn ct_eq_different_lengths() {
assert!(!constant_time_eq(b"hi", b"hello"));
}