use northroot_proof_engine::{
canonicalize_method_shape, canonicalize_span_commitment, canonicalize_trace,
canonicalize_trace_roots, compute_method_shape_hash, compute_span_commitment_hash,
compute_trace_hash, compute_trace_roots_hash, validate_signature_format, MethodShapeManifest,
SignedSpan, SpanCommitment, Trace, TraceRoots,
};
use std::fs;
use std::path::PathBuf;
fn load_golden_file(name: &str) -> String {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("tests");
path.push("golden");
path.push(name);
fs::read_to_string(&path).unwrap_or_else(|e| panic!("Failed to load {}: {}", name, e))
}
#[test]
fn test_posh_workflow() {
let json = load_golden_file("posh_method_shape.json");
let manifest: MethodShapeManifest =
serde_json::from_str(&json).expect("Failed to parse PoSH golden file");
validate_signature_format(&manifest.publisher_sig)
.expect("Publisher signature format should be valid");
let canonical =
canonicalize_method_shape(&manifest).expect("Failed to canonicalize method shape");
let hash = compute_method_shape_hash(&manifest).expect("Failed to compute method shape hash");
assert!(
hash.starts_with("sha256:"),
"Hash should start with sha256: prefix"
);
assert_eq!(
hash.len(),
71,
"Hash should be sha256: + 64 hex chars = 71 chars"
);
let canonical2 = canonicalize_method_shape(&manifest)
.expect("Failed to canonicalize method shape (second time)");
assert_eq!(
canonical, canonical2,
"Canonicalization must be deterministic"
);
let hash2 = compute_method_shape_hash(&manifest)
.expect("Failed to compute method shape hash (second time)");
assert_eq!(hash, hash2, "Hash computation must be deterministic");
}
#[test]
fn test_pox_span_commitment_workflow() {
let json = load_golden_file("pox_span_commitment.json");
let commitment: SpanCommitment =
serde_json::from_str(&json).expect("Failed to parse span commitment golden file");
assert_eq!(commitment.schema_version, "proof.v2");
assert!(!commitment.trace_id.is_empty());
assert!(!commitment.span_id.is_empty());
let canonical =
canonicalize_span_commitment(&commitment).expect("Failed to canonicalize span commitment");
let hash =
compute_span_commitment_hash(&commitment).expect("Failed to compute span commitment hash");
assert!(
hash.starts_with("sha256:"),
"Hash should start with sha256: prefix"
);
assert_eq!(hash.len(), 71, "Hash should be 71 chars");
let canonical2 = canonicalize_span_commitment(&commitment)
.expect("Failed to canonicalize span commitment (second time)");
assert_eq!(
canonical, canonical2,
"Canonicalization must be deterministic"
);
let hash2 = compute_span_commitment_hash(&commitment)
.expect("Failed to compute span commitment hash (second time)");
assert_eq!(hash, hash2, "Hash computation must be deterministic");
}
#[test]
fn test_pox_signed_span_workflow() {
let json = load_golden_file("pox_signed_span.json");
let signed_span: SignedSpan =
serde_json::from_str(&json).expect("Failed to parse signed span golden file");
validate_signature_format(&signed_span.signature).expect("Signature format should be valid");
assert_eq!(signed_span.signature.alg, "ed25519");
assert!(!signed_span.signature.kid.is_empty());
assert!(!signed_span.signature.sig.is_empty());
let hash = compute_span_commitment_hash(&signed_span.commitment)
.expect("Failed to compute span commitment hash");
assert!(
hash.starts_with("sha256:"),
"Hash should start with sha256: prefix"
);
}
#[test]
fn test_pox_trace_workflow() {
let json = load_golden_file("pox_trace.json");
let trace: Trace = serde_json::from_str(&json).expect("Failed to parse trace golden file");
assert_eq!(trace.schema_version, "trace.v2");
assert!(!trace.trace_id.is_empty());
assert!(!trace.method_ref.method_id.is_empty());
let canonical = canonicalize_trace(&trace).expect("Failed to canonicalize trace");
let hash = compute_trace_hash(&trace).expect("Failed to compute trace hash");
assert!(
hash.starts_with("sha256:"),
"Hash should start with sha256: prefix"
);
assert_eq!(hash.len(), 71, "Hash should be 71 chars");
let canonical2 =
canonicalize_trace(&trace).expect("Failed to canonicalize trace (second time)");
assert_eq!(
canonical, canonical2,
"Canonicalization must be deterministic"
);
let hash2 = compute_trace_hash(&trace).expect("Failed to compute trace hash (second time)");
assert_eq!(hash, hash2, "Hash computation must be deterministic");
}
#[test]
fn test_pox_trace_roots_workflow() {
let json = load_golden_file("pox_trace_roots.json");
let roots: TraceRoots =
serde_json::from_str(&json).expect("Failed to parse trace roots golden file");
assert!(!roots.trace_id.is_empty());
assert!(!roots.span_commitments.is_empty());
assert!(!roots.trace_set_root.is_empty());
if let Some(ref id_root) = roots.identity_root {
assert!(!id_root.is_empty());
}
if let Some(ref seq_root) = roots.trace_seq_root {
assert!(!seq_root.is_empty());
}
if let Some(ref sig) = roots.server_sig {
validate_signature_format(sig).expect("Server signature format should be valid");
}
let canonical = canonicalize_trace_roots(&roots).expect("Failed to canonicalize trace roots");
let hash = compute_trace_roots_hash(&roots).expect("Failed to compute trace roots hash");
assert!(
hash.starts_with("sha256:"),
"Hash should start with sha256: prefix"
);
assert_eq!(hash.len(), 71, "Hash should be 71 chars");
let canonical2 =
canonicalize_trace_roots(&roots).expect("Failed to canonicalize trace roots (second time)");
assert_eq!(
canonical, canonical2,
"Canonicalization must be deterministic"
);
let hash2 =
compute_trace_roots_hash(&roots).expect("Failed to compute trace roots hash (second time)");
assert_eq!(hash, hash2, "Hash computation must be deterministic");
}
#[test]
fn test_golden_file_roundtrip() {
let posh_json = load_golden_file("posh_method_shape.json");
let posh: MethodShapeManifest = serde_json::from_str(&posh_json).expect("Failed to parse PoSH");
let _posh_hash = compute_method_shape_hash(&posh).expect("Failed to hash PoSH");
let commitment_json = load_golden_file("pox_span_commitment.json");
let commitment: SpanCommitment =
serde_json::from_str(&commitment_json).expect("Failed to parse span commitment");
let _commitment_hash =
compute_span_commitment_hash(&commitment).expect("Failed to hash span commitment");
let signed_json = load_golden_file("pox_signed_span.json");
let signed: SignedSpan =
serde_json::from_str(&signed_json).expect("Failed to parse signed span");
let _signed_hash =
compute_span_commitment_hash(&signed.commitment).expect("Failed to hash signed span");
let trace_json = load_golden_file("pox_trace.json");
let trace: Trace = serde_json::from_str(&trace_json).expect("Failed to parse trace");
let _trace_hash = compute_trace_hash(&trace).expect("Failed to hash trace");
let roots_json = load_golden_file("pox_trace_roots.json");
let roots: TraceRoots = serde_json::from_str(&roots_json).expect("Failed to parse trace roots");
let _roots_hash = compute_trace_roots_hash(&roots).expect("Failed to hash trace roots");
}