vauban-claim 0.1.0

Vauban Claim Algebra — reference implementation of draft-vauban-claim-algebra-00 (post-quantum claim sextuplet + 5 composition operators, canonical CBOR/JSON codec).
Documentation
//! Codec roundtrip + canonicalisation (8 vectors).

mod common;

use common::fixture_claim;
use vauban_claim::codec::{from_cbor, from_json, to_cbor_canonical, to_json};
use vauban_claim::{Claim, EncodingError};

#[test]
fn c01_cbor_roundtrip_atomic_claim() {
    let claim = fixture_claim();
    let bytes = to_cbor_canonical(&claim).unwrap();
    let back: Claim = from_cbor(&bytes).unwrap();
    assert_eq!(back.subject, claim.subject);
    assert_eq!(back.predicate, claim.predicate);
}

#[test]
fn c02_json_roundtrip_atomic_claim() {
    let claim = fixture_claim();
    let bytes = to_json(&claim).unwrap();
    let back: Claim = from_json(&bytes).unwrap();
    assert_eq!(back.subject, claim.subject);
}

#[test]
fn c03_cbor_canonicalisation_deterministic() {
    let claim = fixture_claim();
    let a = to_cbor_canonical(&claim).unwrap();
    let b = to_cbor_canonical(&claim).unwrap();
    assert_eq!(a, b, "two encodings of the same Claim must be identical");
}

#[test]
fn c04_cbor_canonical_no_floats() {
    // Construct a CBOR value containing a float and try to decode it.
    let mut bytes = Vec::new();
    ciborium::ser::into_writer(&core::f64::consts::PI, &mut bytes).unwrap();
    let res: Result<f64, EncodingError> = from_cbor(&bytes);
    assert!(matches!(res, Err(EncodingError::FloatForbidden)));
}

#[test]
fn c05_claim_ref_stable_under_extension() {
    let claim = fixture_claim();
    let a = claim.claim_ref().unwrap();
    let b = claim.claim_ref().unwrap();
    assert_eq!(a.digest, b.digest);
    assert_eq!(a.digest.len(), 32);
}

#[test]
fn c06_two_distinct_claims_have_distinct_refs() {
    use vauban_claim::ClaimBuilder;
    let a = fixture_claim();
    let b = ClaimBuilder::new()
        .subject(common::fixture_subject_did("did:web:other"))
        .predicate(common::fixture_predicate())
        .evidence(common::fixture_evidence_stark())
        .temporal_frame(common::fixture_temporal(1_700_000_000))
        .revelation_mask(common::fixture_mask_disclose(&["x"]))
        .anchor(common::fixture_anchor())
        .build()
        .unwrap();
    assert_ne!(a.claim_ref().unwrap().digest, b.claim_ref().unwrap().digest);
}

#[test]
fn c07_json_pretty_print_roundtrip() {
    let claim = fixture_claim();
    let s = serde_json::to_string_pretty(&claim).unwrap();
    let back: Claim = serde_json::from_str(&s).unwrap();
    assert_eq!(back.evidence, claim.evidence);
}

#[test]
fn c08_cbor_canonical_sorted_keys() {
    // Round-trip through Value to confirm canonical encoding does not
    // depend on Rust struct field declaration order.
    let claim = fixture_claim();
    let bytes = to_cbor_canonical(&claim).unwrap();
    // Re-decode → re-encode through canonical → must be byte-identical.
    let back: Claim = from_cbor(&bytes).unwrap();
    let bytes2 = to_cbor_canonical(&back).unwrap();
    assert_eq!(bytes, bytes2);
}