use northroot_proof_engine::{
canonicalize_span_shape, compute_data_shape_hash, compute_sha256, normalize_timestamp,
validate_iso_time, validate_sha256_format, validate_span_id, validate_trace_id, SpanShape,
};
use proptest::prelude::*;
proptest! {
#![proptest_config(ProptestConfig {
cases: 100,
failure_persistence: None,
..ProptestConfig::default()
})]
#[test]
fn fuzz_canonicalization_no_panic(
tool_id in "[a-zA-Z0-9._-]{0,50}",
tool_version in "[a-zA-Z0-9._-]{0,20}",
checker_ref in prop::option::of("[a-zA-Z0-9:@-]{0,50}")
) {
let shape = SpanShape {
tool_id,
tool_version,
param_schema: serde_json::json!({"key": "value"}),
checker_ref,
};
let _result = canonicalize_span_shape(&shape);
}
#[test]
fn fuzz_hash_computation_deterministic(
text in "[a-zA-Z0-9 ]{0,1000}"
) {
let hash1 = compute_sha256(&text);
let hash2 = compute_sha256(&text);
assert_eq!(hash1, hash2);
assert!(hash1.starts_with("sha256:"));
assert_eq!(hash1.len(), 71);
}
#[test]
fn fuzz_validation_no_panic(
id in "[a-zA-Z0-9_-]{0,200}"
) {
let _trace_result = validate_trace_id(&id);
let _span_result = validate_span_id(&id);
}
#[test]
fn fuzz_timestamp_normalization_no_panic(
timestamp in "[a-zA-Z0-9:+-.TZ]{0,100}"
) {
let _result = normalize_timestamp(×tamp);
}
#[test]
fn fuzz_sha256_format_validation(
hash_str in "[a-zA-Z0-9:]{0,200}"
) {
let _result = validate_sha256_format(&hash_str);
}
#[test]
fn fuzz_iso_time_validation(
time_str in "[a-zA-Z0-9:+-.TZ]{0,100}"
) {
let _result = validate_iso_time(&time_str);
}
#[test]
fn fuzz_data_shape_hash_no_panic(
schema_str in "[a-zA-Z0-9{}:,\"\\[\\] ]{0,500}"
) {
if let Ok(schema_json) = serde_json::from_str::<serde_json::Value>(&schema_str) {
let _result = compute_data_shape_hash(&schema_json, None);
}
}
}
#[test]
fn fuzz_signature_verification_malformed_data() {
use northroot_proof_engine::{verify_signature, Signature};
let malformed_sigs = vec![
Signature {
alg: "ed25519".to_string(),
kid: "".to_string(), sig: "invalid".to_string(),
},
Signature {
alg: "invalid".to_string(), kid: "did:key:zTest".to_string(),
sig: "dGVzdA".to_string(),
},
Signature {
alg: "ed25519".to_string(),
kid: "did:key:zTest".to_string(),
sig: "not-base64url".to_string(), },
];
let message = b"test message";
let key_bytes = [0u8; 32];
for sig in malformed_sigs {
let result = verify_signature(message, &sig, &key_bytes);
assert!(result.is_err(), "Malformed signature should return error");
}
}
#[test]
fn fuzz_validation_edge_cases() {
assert!(validate_trace_id("").is_err());
assert!(validate_span_id("").is_err());
let long_id = "a".repeat(10000);
let _ = validate_trace_id(&long_id); let _ = validate_span_id(&long_id);
let special_chars = "!@#$%^&*()[]{}|\\:;\"'<>?,./";
assert!(validate_trace_id(special_chars).is_err());
assert!(validate_span_id(special_chars).is_err());
let unicode = "测试_123";
let _ = validate_trace_id(unicode); let _ = validate_span_id(unicode); }
#[test]
fn fuzz_canonicalization_determinism() {
use northroot_proof_engine::canonicalize_span_shape;
let shape = SpanShape {
tool_id: "test".to_string(),
tool_version: "1".to_string(),
param_schema: serde_json::json!({"key": "value"}),
checker_ref: None,
};
let results: Vec<_> = (0..100).map(|_| canonicalize_span_shape(&shape)).collect();
for result in &results {
assert!(result.is_ok());
}
let first = results[0].as_ref().unwrap();
for result in &results[1..] {
assert_eq!(first, result.as_ref().unwrap());
}
}
#[test]
fn fuzz_hash_performance_bounds() {
use std::time::Instant;
let test_data = "x".repeat(10000);
let start = Instant::now();
let _hash = compute_sha256(&test_data);
let duration = start.elapsed();
assert!(duration.as_millis() < 100, "Hash computation took too long");
}