#![deny(unsafe_code)]
#![deny(missing_docs)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::panic)]
use crate::prelude::error::{LatticeArcError, Result};
#[cfg(not(feature = "fips"))]
use crate::primitives::ec::secp256k1::{Secp256k1KeyPair, Secp256k1Signature};
use crate::primitives::ec::{
ed25519::{Ed25519KeyPair, Ed25519Signature},
traits::{EcKeyPair, EcSignature},
};
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct UtilityTestVector {
pub test_case_id: String,
pub function: String,
pub input_data: Vec<u8>,
pub expected_output: Vec<u8>,
pub parameters: HashMap<String, String>,
}
#[derive(Debug, Clone)]
pub struct CryptoTestVector {
pub test_case_id: String,
pub algorithm: String,
pub operation: String,
pub private_key: Vec<u8>,
pub public_key: Vec<u8>,
pub message: Vec<u8>,
pub signature: Vec<u8>,
pub expected_result: bool,
pub parameters: HashMap<String, String>,
}
pub struct UtilityCavpTester {
test_vectors: Vec<UtilityTestVector>,
results: HashMap<String, bool>,
}
impl UtilityCavpTester {
#[must_use]
pub fn new() -> Self {
Self { test_vectors: Vec::new(), results: HashMap::new() }
}
pub fn load_test_vectors(&mut self, vectors: Vec<UtilityTestVector>) {
self.test_vectors = vectors;
}
pub fn run_compliance_tests(&mut self) -> Result<()> {
tracing::info!("Running utility CAVP compliance tests");
for vector in &self.test_vectors {
let result = Self::run_single_test(vector)?;
self.results.insert(vector.test_case_id.clone(), result);
if result {
tracing::info!("Test {}: PASSED", vector.test_case_id);
} else {
tracing::error!("Test {}: FAILED", vector.test_case_id);
return Err(LatticeArcError::VerificationFailed(format!(
"CAVP test {} failed",
vector.test_case_id
)));
}
}
Ok(())
}
#[must_use]
pub fn generate_report(&self) -> String {
let mut report = String::from("# Utility CAVP Compliance Test Report\n\n");
report.push_str(&format!("Total Tests: {}\n", self.test_vectors.len()));
report.push_str(&format!("Passed: {}\n", self.results.values().filter(|&&v| v).count()));
report.push_str(&format!("Failed: {}\n\n", self.results.values().filter(|&&v| !v).count()));
report.push_str("## Test Results\n\n");
for (test_id, passed) in &self.results {
let status = if *passed { "✅ PASSED" } else { "❌ FAILED" };
report.push_str(&format!("- {}: {}\n", test_id, status));
}
report
}
fn run_single_test(vector: &UtilityTestVector) -> Result<bool> {
match vector.function.as_str() {
"hex_encode" => Ok(Self::test_hex_encode_succeeds(vector)),
"hex_decode" => Self::test_hex_decode_succeeds(vector),
"uuid_generate" => Ok(Self::test_uuid_generate_succeeds()),
"version_check" => Ok(Self::test_version_check_succeeds(vector)),
"domain_constant" => Self::test_domain_constant_succeeds(vector),
_ => Err(LatticeArcError::InvalidConfiguration(format!(
"Unsupported utility function: {}",
vector.function
))),
}
}
fn test_hex_encode_succeeds(vector: &UtilityTestVector) -> bool {
let encoded = hex::encode(&vector.input_data);
let encoded_bytes = encoded.as_bytes();
encoded_bytes == &vector.expected_output[..]
}
fn test_hex_decode_succeeds(vector: &UtilityTestVector) -> Result<bool> {
let hex_string = std::str::from_utf8(&vector.input_data)
.map_err(|e| LatticeArcError::InvalidData(format!("Invalid hex string: {}", e)))?;
let decoded = hex::decode(hex_string)?;
Ok(decoded == vector.expected_output)
}
fn test_uuid_generate_succeeds() -> bool {
let uuid = uuid::Uuid::new_v4();
if uuid.is_nil() {
return false;
}
if uuid.get_version_num() != 4 {
return false;
}
let uuid_str = uuid.to_string();
if uuid_str.len() != 36 {
return false;
}
let chars: Vec<char> = uuid_str.chars().collect();
if chars.get(8) != Some(&'-')
|| chars.get(13) != Some(&'-')
|| chars.get(18) != Some(&'-')
|| chars.get(23) != Some(&'-')
{
return false;
}
true
}
fn test_version_check_succeeds(vector: &UtilityTestVector) -> bool {
let expected_version = vector.expected_output.first().copied();
let expected = expected_version.unwrap_or(1);
crate::prelude::ENVELOPE_FORMAT_VERSION == expected
}
fn test_domain_constant_succeeds(vector: &UtilityTestVector) -> Result<bool> {
let domain_name = std::str::from_utf8(&vector.input_data)
.map_err(|e| LatticeArcError::InvalidData(format!("Invalid domain name: {}", e)))?;
let domain_constant = match domain_name {
"HYBRID_KEM" => crate::types::domains::HYBRID_KEM,
"CASCADE_OUTER" => crate::types::domains::CASCADE_OUTER,
"CASCADE_INNER" => crate::types::domains::CASCADE_INNER,
"SIGNATURE_BIND" => crate::types::domains::SIGNATURE_BIND,
_ => return Ok(false),
};
Ok(domain_constant == &vector.expected_output[..])
}
}
impl Default for UtilityCavpTester {
fn default() -> Self {
Self::new()
}
}
pub struct CryptoCavpTester {
test_vectors: Vec<CryptoTestVector>,
results: HashMap<String, bool>,
}
impl CryptoCavpTester {
#[must_use]
pub fn new() -> Self {
Self { test_vectors: Vec::new(), results: HashMap::new() }
}
pub fn load_test_vectors(&mut self, vectors: Vec<CryptoTestVector>) {
self.test_vectors = vectors;
}
pub fn run_compliance_tests(&mut self) -> Result<()> {
tracing::info!("Running cryptographic CAVP compliance tests");
for vector in &self.test_vectors {
let result = Self::run_single_test(vector)?;
self.results.insert(vector.test_case_id.clone(), result);
if result {
tracing::info!("Test {}: PASSED", vector.test_case_id);
} else {
tracing::error!("Test {}: FAILED", vector.test_case_id);
return Err(LatticeArcError::VerificationFailed(format!(
"CAVP test {} failed",
vector.test_case_id
)));
}
}
Ok(())
}
#[must_use]
pub fn generate_report(&self) -> String {
let mut report = String::from("# Cryptographic CAVP Compliance Test Report\n\n");
report.push_str(&format!("Total Tests: {}\n", self.test_vectors.len()));
report.push_str(&format!("Passed: {}\n", self.results.values().filter(|&&v| v).count()));
report.push_str(&format!("Failed: {}\n\n", self.results.values().filter(|&&v| !v).count()));
report.push_str("## Test Results\n\n");
for (test_id, passed) in &self.results {
let status = if *passed { "✅ PASSED" } else { "❌ FAILED" };
report.push_str(&format!("- {}: {}\n", test_id, status));
}
report
}
fn run_single_test(vector: &CryptoTestVector) -> Result<bool> {
match vector.algorithm.as_str() {
#[cfg(not(feature = "fips"))]
"ECDSA-secp256k1" => Self::run_ecdsa_test(vector),
"Ed25519" => Self::run_ed25519_test(vector),
_ => Err(LatticeArcError::InvalidConfiguration(format!(
"Unsupported algorithm: {}",
vector.algorithm
))),
}
}
#[cfg(not(feature = "fips"))]
fn run_ecdsa_test(vector: &CryptoTestVector) -> Result<bool> {
match vector.operation.as_str() {
"sign" => {
let keypair =
Secp256k1KeyPair::from_secret_key(&vector.private_key).map_err(|e| {
LatticeArcError::InvalidData(format!("Invalid ECDSA private key: {e}"))
})?;
let signature = keypair.sign(&vector.message).map_err(|e| {
LatticeArcError::InvalidData(format!("ECDSA signing failed: {e}"))
})?;
let signature_bytes = Secp256k1Signature::signature_bytes(&signature);
Ok(!signature_bytes.is_empty() && signature_bytes.len() == 64)
}
"verify" => {
let signature = Secp256k1Signature::signature_from_bytes(&vector.signature)
.map_err(|e| {
LatticeArcError::InvalidData(format!("Invalid ECDSA signature: {e}"))
})?;
let result =
Secp256k1Signature::verify(&vector.public_key, &vector.message, &signature)
.is_ok();
Ok(result == vector.expected_result)
}
_ => Err(LatticeArcError::InvalidConfiguration(format!(
"Unsupported ECDSA operation: {}",
vector.operation
))),
}
}
fn run_ed25519_test(vector: &CryptoTestVector) -> Result<bool> {
match vector.operation.as_str() {
"sign" => {
let keypair =
Ed25519KeyPair::from_secret_key(&vector.private_key).map_err(|e| {
LatticeArcError::InvalidData(format!("Invalid Ed25519 private key: {e}"))
})?;
let signature = keypair.sign(&vector.message);
let signature_bytes = Ed25519Signature::signature_bytes(&signature);
Ok(!signature_bytes.is_empty() && signature_bytes.len() == 64)
}
"verify" => {
let signature =
Ed25519Signature::signature_from_bytes(&vector.signature).map_err(|e| {
LatticeArcError::InvalidData(format!("Invalid Ed25519 signature: {e}"))
})?;
let result =
Ed25519Signature::verify(&vector.public_key, &vector.message, &signature)
.is_ok();
Ok(result == vector.expected_result)
}
_ => Err(LatticeArcError::InvalidConfiguration(format!(
"Unsupported Ed25519 operation: {}",
vector.operation
))),
}
}
}
impl Default for CryptoCavpTester {
fn default() -> Self {
Self::new()
}
}
#[must_use]
pub fn load_sample_utility_vectors() -> Vec<UtilityTestVector> {
vec![
UtilityTestVector {
test_case_id: "HEX-ENCODE-001".to_string(),
function: "hex_encode".to_string(),
input_data: vec![255, 0, 127, 64],
expected_output: b"ff007f40".to_vec(),
parameters: HashMap::new(),
},
UtilityTestVector {
test_case_id: "HEX-DECODE-001".to_string(),
function: "hex_decode".to_string(),
input_data: b"deadbeef".to_vec(),
expected_output: vec![222, 173, 190, 239],
parameters: HashMap::new(),
},
UtilityTestVector {
test_case_id: "UUID-GENERATE-001".to_string(),
function: "uuid_generate".to_string(),
input_data: vec![],
expected_output: vec![], parameters: HashMap::new(),
},
UtilityTestVector {
test_case_id: "VERSION-CHECK-001".to_string(),
function: "version_check".to_string(),
input_data: vec![],
expected_output: vec![1], parameters: HashMap::new(),
},
UtilityTestVector {
test_case_id: "DOMAIN-CONSTANT-001".to_string(),
function: "domain_constant".to_string(),
input_data: b"HYBRID_KEM".to_vec(),
expected_output: crate::types::domains::HYBRID_KEM.to_vec(),
parameters: HashMap::new(),
},
]
}
pub fn load_sample_crypto_vectors() -> Result<Vec<CryptoTestVector>> {
let private_key_bytes: [u8; 32] = [
9, 97, 177, 25, 223, 90, 213, 253, 245, 253, 166, 186, 10, 175, 250, 145, 70, 102, 73, 89,
73, 148, 90, 236, 60, 48, 59, 122, 175, 96, 1, 0,
];
let keypair = Ed25519KeyPair::from_secret_key(&private_key_bytes).map_err(|e| {
LatticeArcError::InvalidData(format!("Ed25519 key construction failed: {}", e))
})?;
let message = b"test message for Ed25519".to_vec();
let signature = keypair.sign(&message);
let signature_bytes = Ed25519Signature::signature_bytes(&signature);
let public_key_bytes_vec = keypair.public_key_bytes();
#[cfg(not(feature = "fips"))]
let ecdsa_private_key: [u8; 32] = [
0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, 0x67, 0xb1, 0xd6,
0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f,
0x67, 0x21,
];
#[cfg(not(feature = "fips"))]
let ecdsa_vector = CryptoTestVector {
test_case_id: "ECDSA-SECP256K1-SIGN-001".to_string(),
algorithm: "ECDSA-secp256k1".to_string(),
operation: "sign".to_string(),
private_key: ecdsa_private_key.to_vec(),
public_key: vec![], message: b"test message for ECDSA".to_vec(),
signature: vec![], expected_result: true,
parameters: HashMap::new(),
};
#[cfg_attr(feature = "fips", allow(unused_mut))]
let mut vectors = vec![
CryptoTestVector {
test_case_id: "ED25519-SIGN-001".to_string(),
algorithm: "Ed25519".to_string(),
operation: "sign".to_string(),
private_key: private_key_bytes.to_vec(),
public_key: vec![], message: message.clone(),
signature: vec![], expected_result: true,
parameters: HashMap::new(),
},
CryptoTestVector {
test_case_id: "ED25519-VERIFY-001".to_string(),
algorithm: "Ed25519".to_string(),
operation: "verify".to_string(),
private_key: vec![], public_key: public_key_bytes_vec,
message,
signature: signature_bytes,
expected_result: true,
parameters: HashMap::new(),
},
];
#[cfg(not(feature = "fips"))]
vectors.insert(0, ecdsa_vector);
Ok(vectors)
}
pub struct UtilityValidator;
impl Default for UtilityValidator {
fn default() -> Self {
Self::new()
}
}
impl UtilityValidator {
#[must_use]
pub fn new() -> Self {
Self {}
}
pub fn validate_utilities(&self) -> Result<()> {
tracing::info!("Validating utility functions");
tracing::info!("All utility functions validated successfully");
tracing::info!("CAVP-style utility testing completed successfully");
Ok(())
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)] mod tests {
use super::*;
#[test]
fn test_utility_validator_succeeds() {
let validator = UtilityValidator::new();
assert!(validator.validate_utilities().is_ok());
}
#[test]
fn test_cavp_utility_testing_succeeds() {
let validator = UtilityValidator::new();
assert!(validator.validate_utilities().is_ok());
}
#[test]
fn test_hex_functions_roundtrip_succeeds() {
let data = vec![255, 0, 127, 64];
let encoded = hex::encode(&data);
assert_eq!(encoded, "ff007f40");
let decoded = hex::decode(&encoded).unwrap();
assert_eq!(decoded, data);
}
#[test]
fn test_uuid_validation_has_correct_format() {
let uuid = uuid::Uuid::new_v4();
assert!(!uuid.is_nil());
assert_eq!(uuid.get_version_num(), 4);
let uuid_str = uuid.to_string();
assert_eq!(uuid_str.len(), 36);
assert_eq!(uuid_str.chars().nth(8), Some('-'));
assert_eq!(uuid_str.chars().nth(13), Some('-'));
assert_eq!(uuid_str.chars().nth(18), Some('-'));
assert_eq!(uuid_str.chars().nth(23), Some('-'));
}
#[test]
fn test_domain_constants_have_correct_values_succeeds() {
use crate::types::domains;
assert!(!domains::HYBRID_KEM.is_empty());
assert!(!domains::CASCADE_OUTER.is_empty());
assert!(!domains::CASCADE_INNER.is_empty());
assert!(!domains::SIGNATURE_BIND.is_empty());
assert!(domains::HYBRID_KEM.windows(12).any(|w| w == b"LatticeArc-v"));
assert!(domains::CASCADE_OUTER.windows(12).any(|w| w == b"LatticeArc-v"));
assert!(domains::CASCADE_INNER.windows(12).any(|w| w == b"LatticeArc-v"));
assert!(domains::SIGNATURE_BIND.windows(12).any(|w| w == b"LatticeArc-v"));
}
#[test]
fn test_version_constant_is_positive_succeeds() {
const { assert!(crate::prelude::ENVELOPE_FORMAT_VERSION > 0) };
}
#[test]
fn test_crypto_cavp_tester_succeeds() {
let mut tester = CryptoCavpTester::new();
let vectors = load_sample_crypto_vectors().unwrap();
tester.load_test_vectors(vectors);
assert!(tester.run_compliance_tests().is_ok());
}
#[test]
fn test_utility_cavp_tester_default_is_empty() {
let tester = UtilityCavpTester::default();
assert!(tester.test_vectors.is_empty());
assert!(tester.results.is_empty());
}
#[test]
fn test_utility_cavp_tester_load_and_run_succeeds() {
let mut tester = UtilityCavpTester::new();
let vectors = load_sample_utility_vectors();
tester.load_test_vectors(vectors);
assert!(tester.run_compliance_tests().is_ok());
}
#[test]
fn test_utility_cavp_tester_generate_report_succeeds() {
let mut tester = UtilityCavpTester::new();
let vectors = load_sample_utility_vectors();
tester.load_test_vectors(vectors);
tester.run_compliance_tests().unwrap();
let report = tester.generate_report();
assert!(report.contains("Utility CAVP Compliance Test Report"));
assert!(report.contains("Total Tests:"));
assert!(report.contains("Passed:"));
assert!(report.contains("PASSED"));
}
#[test]
fn test_utility_cavp_empty_run_succeeds() {
let mut tester = UtilityCavpTester::new();
assert!(tester.run_compliance_tests().is_ok());
let report = tester.generate_report();
assert!(report.contains("Total Tests: 0"));
}
#[test]
fn test_utility_cavp_hex_encode_vector_succeeds() {
let mut tester = UtilityCavpTester::new();
tester.load_test_vectors(vec![UtilityTestVector {
test_case_id: "HEX-CUSTOM-001".to_string(),
function: "hex_encode".to_string(),
input_data: vec![0xDE, 0xAD],
expected_output: b"dead".to_vec(),
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_ok());
}
#[test]
fn test_utility_cavp_hex_decode_vector_succeeds() {
let mut tester = UtilityCavpTester::new();
tester.load_test_vectors(vec![UtilityTestVector {
test_case_id: "HEX-DEC-001".to_string(),
function: "hex_decode".to_string(),
input_data: b"cafe".to_vec(),
expected_output: vec![0xCA, 0xFE],
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_ok());
}
#[test]
fn test_utility_cavp_uuid_vector_succeeds() {
let mut tester = UtilityCavpTester::new();
tester.load_test_vectors(vec![UtilityTestVector {
test_case_id: "UUID-001".to_string(),
function: "uuid_generate".to_string(),
input_data: vec![],
expected_output: vec![],
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_ok());
}
#[test]
fn test_utility_cavp_version_check_vector_succeeds() {
let mut tester = UtilityCavpTester::new();
tester.load_test_vectors(vec![UtilityTestVector {
test_case_id: "VER-001".to_string(),
function: "version_check".to_string(),
input_data: vec![],
expected_output: vec![crate::prelude::ENVELOPE_FORMAT_VERSION],
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_ok());
}
#[test]
fn test_utility_cavp_domain_constant_vectors_succeeds() {
use crate::types::domains;
for (name, expected) in [
("HYBRID_KEM", domains::HYBRID_KEM.to_vec()),
("CASCADE_OUTER", domains::CASCADE_OUTER.to_vec()),
("CASCADE_INNER", domains::CASCADE_INNER.to_vec()),
("SIGNATURE_BIND", domains::SIGNATURE_BIND.to_vec()),
] {
let mut tester = UtilityCavpTester::new();
tester.load_test_vectors(vec![UtilityTestVector {
test_case_id: format!("DOMAIN-{}", name),
function: "domain_constant".to_string(),
input_data: name.as_bytes().to_vec(),
expected_output: expected,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_ok(), "Failed for domain {}", name);
}
}
#[test]
fn test_utility_cavp_unknown_domain_returns_error() {
let mut tester = UtilityCavpTester::new();
tester.load_test_vectors(vec![UtilityTestVector {
test_case_id: "DOMAIN-UNKNOWN".to_string(),
function: "domain_constant".to_string(),
input_data: b"UNKNOWN_DOMAIN".to_vec(),
expected_output: vec![],
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_utility_cavp_unsupported_function_returns_error() {
let mut tester = UtilityCavpTester::new();
tester.load_test_vectors(vec![UtilityTestVector {
test_case_id: "UNSUPPORTED-001".to_string(),
function: "unsupported_function".to_string(),
input_data: vec![],
expected_output: vec![],
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_utility_cavp_hex_encode_mismatch_returns_error() {
let mut tester = UtilityCavpTester::new();
tester.load_test_vectors(vec![UtilityTestVector {
test_case_id: "HEX-FAIL-001".to_string(),
function: "hex_encode".to_string(),
input_data: vec![0xFF],
expected_output: b"00".to_vec(), parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_crypto_cavp_tester_default_is_empty() {
let tester = CryptoCavpTester::default();
assert!(tester.test_vectors.is_empty());
}
#[test]
fn test_crypto_cavp_generate_report_succeeds() {
let mut tester = CryptoCavpTester::new();
let vectors = load_sample_crypto_vectors().unwrap();
tester.load_test_vectors(vectors);
tester.run_compliance_tests().unwrap();
let report = tester.generate_report();
assert!(report.contains("Cryptographic CAVP Compliance Test Report"));
assert!(report.contains("PASSED"));
}
#[test]
fn test_crypto_cavp_empty_run_succeeds() {
let mut tester = CryptoCavpTester::new();
assert!(tester.run_compliance_tests().is_ok());
}
#[test]
fn test_crypto_cavp_unsupported_algorithm_returns_error() {
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "UNSUP-001".to_string(),
algorithm: "RSA-2048".to_string(),
operation: "sign".to_string(),
private_key: vec![],
public_key: vec![],
message: vec![],
signature: vec![],
expected_result: true,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_crypto_cavp_ecdsa_unsupported_operation_returns_error() {
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "ECDSA-BAD-OP".to_string(),
algorithm: "ECDSA-secp256k1".to_string(),
operation: "encrypt".to_string(),
private_key: vec![0xC9; 32],
public_key: vec![],
message: vec![],
signature: vec![],
expected_result: true,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_crypto_cavp_ed25519_unsupported_operation_returns_error() {
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "ED-BAD-OP".to_string(),
algorithm: "Ed25519".to_string(),
operation: "encrypt".to_string(),
private_key: vec![0x01; 32],
public_key: vec![],
message: vec![],
signature: vec![],
expected_result: true,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_crypto_cavp_ecdsa_invalid_key_returns_error() {
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "ECDSA-BAD-KEY".to_string(),
algorithm: "ECDSA-secp256k1".to_string(),
operation: "sign".to_string(),
private_key: vec![0; 32], public_key: vec![],
message: b"test".to_vec(),
signature: vec![],
expected_result: true,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_crypto_cavp_ed25519_wrong_key_length_returns_error() {
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "ED-BAD-LEN".to_string(),
algorithm: "Ed25519".to_string(),
operation: "sign".to_string(),
private_key: vec![1; 16], public_key: vec![],
message: b"test".to_vec(),
signature: vec![],
expected_result: true,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_load_sample_utility_vectors_are_not_empty_matches_expected() {
let vectors = load_sample_utility_vectors();
assert!(!vectors.is_empty());
let ids: Vec<&str> = vectors.iter().map(|v| v.test_case_id.as_str()).collect();
assert!(ids.contains(&"HEX-ENCODE-001"));
assert!(ids.contains(&"HEX-DECODE-001"));
assert!(ids.contains(&"UUID-GENERATE-001"));
}
#[test]
fn test_load_sample_crypto_vectors_are_not_empty_matches_expected() {
let vectors = load_sample_crypto_vectors().unwrap();
assert!(!vectors.is_empty());
let ids: Vec<&str> = vectors.iter().map(|v| v.test_case_id.as_str()).collect();
#[cfg(not(feature = "fips"))]
assert!(ids.contains(&"ECDSA-SECP256K1-SIGN-001"));
assert!(ids.contains(&"ED25519-SIGN-001"));
assert!(ids.contains(&"ED25519-VERIFY-001"));
}
#[test]
#[cfg(not(feature = "fips"))]
fn test_crypto_cavp_ecdsa_verify_valid_succeeds() {
use crate::primitives::ec::secp256k1::Secp256k1KeyPair as TestKeyPair;
use crate::primitives::ec::secp256k1::Secp256k1Signature as TestSig;
use crate::primitives::ec::traits::{EcKeyPair, EcSignature};
let private_key: [u8; 32] = [
0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, 0x67, 0xb1,
0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, 0x7b, 0x8a, 0x62, 0x2b,
0x12, 0x0f, 0x67, 0x21,
];
let keypair = TestKeyPair::from_secret_key(&private_key).unwrap();
let message = b"test message for ECDSA verify";
let signature = keypair.sign(message).unwrap();
let verifying_key = keypair.public_key_bytes();
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "ECDSA-VERIFY-001".to_string(),
algorithm: "ECDSA-secp256k1".to_string(),
operation: "verify".to_string(),
private_key: vec![],
public_key: verifying_key.to_vec(),
message: message.to_vec(),
signature: TestSig::signature_bytes(&signature),
expected_result: true,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_ok());
}
#[test]
#[cfg(not(feature = "fips"))]
fn test_crypto_cavp_ecdsa_verify_invalid_signature_returns_error() {
use crate::primitives::ec::secp256k1::Secp256k1KeyPair as TestKeyPair;
use crate::primitives::ec::secp256k1::Secp256k1Signature as TestSig;
use crate::primitives::ec::traits::{EcKeyPair, EcSignature};
let private_key: [u8; 32] = [
0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, 0x67, 0xb1,
0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, 0x7b, 0x8a, 0x62, 0x2b,
0x12, 0x0f, 0x67, 0x21,
];
let keypair = TestKeyPair::from_secret_key(&private_key).unwrap();
let message = b"test message for ECDSA verify";
let signature = keypair.sign(message).unwrap();
let verifying_key = keypair.public_key_bytes();
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "ECDSA-VERIFY-FAIL".to_string(),
algorithm: "ECDSA-secp256k1".to_string(),
operation: "verify".to_string(),
private_key: vec![],
public_key: verifying_key.to_vec(),
message: b"wrong message".to_vec(),
signature: TestSig::signature_bytes(&signature),
expected_result: false, parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_ok());
}
#[test]
fn test_crypto_cavp_ecdsa_verify_invalid_public_key_returns_error() {
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "ECDSA-BAD-PK".to_string(),
algorithm: "ECDSA-secp256k1".to_string(),
operation: "verify".to_string(),
private_key: vec![],
public_key: vec![0xFF; 10], message: b"test".to_vec(),
signature: vec![0; 64],
expected_result: true,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_crypto_cavp_ecdsa_verify_invalid_signature_bytes_returns_error() {
use k256::ecdsa::SigningKey as EcdsaSigningKey;
let private_key: [u8; 32] = [
0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57, 0x67, 0xb1,
0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, 0x7b, 0x8a, 0x62, 0x2b,
0x12, 0x0f, 0x67, 0x21,
];
let signing_key = EcdsaSigningKey::from_slice(&private_key).unwrap();
let verifying_key = signing_key.verifying_key();
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "ECDSA-BAD-SIG".to_string(),
algorithm: "ECDSA-secp256k1".to_string(),
operation: "verify".to_string(),
private_key: vec![],
public_key: verifying_key.to_sec1_bytes().to_vec(),
message: b"test".to_vec(),
signature: vec![0xFF; 10], expected_result: true,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_crypto_cavp_ed25519_verify_wrong_pk_length_returns_error() {
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "ED-BAD-PK-LEN".to_string(),
algorithm: "Ed25519".to_string(),
operation: "verify".to_string(),
private_key: vec![],
public_key: vec![1; 16], message: b"test".to_vec(),
signature: vec![0; 64],
expected_result: true,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_crypto_cavp_ed25519_verify_wrong_sig_length_returns_error() {
let mut tester = CryptoCavpTester::new();
tester.load_test_vectors(vec![CryptoTestVector {
test_case_id: "ED-BAD-SIG-LEN".to_string(),
algorithm: "Ed25519".to_string(),
operation: "verify".to_string(),
private_key: vec![],
public_key: vec![1; 32],
message: b"test".to_vec(),
signature: vec![0; 10], expected_result: true,
parameters: HashMap::new(),
}]);
assert!(tester.run_compliance_tests().is_err());
}
#[test]
fn test_utility_test_vector_clone_debug_succeeds() {
let vector = UtilityTestVector {
test_case_id: "TEST-001".to_string(),
function: "hex_encode".to_string(),
input_data: vec![1, 2, 3],
expected_output: b"010203".to_vec(),
parameters: HashMap::new(),
};
let cloned = vector.clone();
assert_eq!(cloned.test_case_id, "TEST-001");
assert_eq!(cloned.function, "hex_encode");
let debug = format!("{:?}", vector);
assert!(debug.contains("UtilityTestVector"));
}
#[test]
fn test_crypto_test_vector_clone_debug_succeeds() {
let vector = CryptoTestVector {
test_case_id: "CRYPTO-001".to_string(),
algorithm: "Ed25519".to_string(),
operation: "sign".to_string(),
private_key: vec![1; 32],
public_key: vec![],
message: b"msg".to_vec(),
signature: vec![],
expected_result: true,
parameters: HashMap::new(),
};
let cloned = vector.clone();
assert_eq!(cloned.algorithm, "Ed25519");
let debug = format!("{:?}", vector);
assert!(debug.contains("CryptoTestVector"));
}
}