open-standards/smart-byte/smart-byte-rs/crates/smart-byte-mdl/tests/round_trip.rs
Transaction Science 6575ff1eb7 Ingest batch 3: 9 more crates across openpay / smart-byte / eoc
openpay/ (+3 crates)
  op-bnpl/        Affirm + Klarna + Afterpay/Clearpay rails. Full lifecycle
                  typestate (Initiated→Approved→Captured→Settled→Refunded).
                  Per-provider sandbox+production base URLs, regions (NA/EU/OC
                  for Klarna; US/AuNz/Gb/Ca/Eu for Afterpay). HMAC-SHA256
                  webhook verification with constant-time compare. 61 tests.
  op-batch/       NACHA ACH (94-char records, PPD/CCD/WEB/TEL/CTX, R01-R99
                  return codes, Same-Day ACH cutoffs); SEPA pain.001.001.09
                  (CT) + pain.008.001.08 (DD) with SCT-Inst flagging; Fedwire
                  MT103/MT202/CHIPS + pacs.008.001.12 / pacs.009.001.10 +
                  UETR; Bacs Standard 18. Per-rail cutoff scheduler. Exception
                  taxonomy unified across rails. 51 tests.
  op-screening/   OFAC SDN + EU consolidated + UN consolidated + HMT UK
                  consolidated + Australia DFAT + Canada SEMA + Japan MOF.
                  Levenshtein + Jaro-Winkler + Soundex + Metaphone + token
                  Jaccard scoring. Unicode NFKD normalisation + Cyrillic /
                  Arabic transliteration. Ed25519-signed BLAKE3-chained
                  audit log. BSA helpers: CTR + SAR pattern detection
                  (structuring, round-dollar, rapid-in-out). 43 tests.

smart-byte/smart-byte-rs/ (+3 crates)
  smart-byte-bbs/      BBS+ signatures (IETF draft-irtf-cfrg-bbs-signatures-08).
                       BLS12-381 keys, signatures, disclosure proofs with
                       cryptographic unlinkability. bbs-2023 Data Integrity
                       cryptosuite. AnonCreds-shaped link secrets +
                       predicate proofs. SecretKey zeroize-on-drop. 49 tests.
  smart-byte-didcomm/  DIDComm v2 messaging per DIF spec. Pack-encrypted
                       (ECDH-1PU + ECDH-ES via X25519), pack-signed (JWS),
                       pack-plaintext. Aries protocols: issue-credential v3,
                       present-proof v3, basic-message, trust-ping, discover-
                       features, out-of-band, coordinate-mediation, message-
                       pickup. Mediator role with pluggable storage. 23 tests.
  smart-byte-mdl/      ISO/IEC 18013-5 mobile driver's licence + 18013-7
                       online presentment. mDoc + MSO with salted-hash
                       selective disclosure (per item; SHA-256 digest tree).
                       org.iso.18013.5.1 namespace + AAMVA add-on. ES256
                       device-auth + issuer-auth. QR-code device-engagement
                       scaffolding. 28 tests.

eoc/eoc-rs/ (+3 crates)
  eoc-local/      Local-inference backends behind one NeuralBackend:
                  llama.cpp (GGUF, Q4/Q5/Q6/Q8/F16/F32 quantisation),
                  MLX (Apple Silicon, feature-gated), MLC-LLM (TVM, feature-
                  gated marker), ONNX Runtime. GGUF file-format reader.
                  HuggingFace tokenizers. Greedy / top-k / top-p / temperature /
                  Mirostat samplers. Model registry scanning ~/.eoc/models/.
                  Joule attribution via eoc-meter. 39 tests.
  eoc-rerank/     BM25 sparse + HNSW dense + RRF + min-max hybrid fusion.
                  Cohere v3.5 + Voyage v2 + bge-reranker v2-m3 + ms-marco
                  MiniLM + ColBERT v2 rerankers. Two-stage pipeline:
                  retrieve top-K hybrid → cross-encoder rerank → top-N.
                  KV-stage recovery shim into the cascade. 31 tests.
  eoc-eval/       15 canonical eval harnesses: MMLU, MMLU-Pro, GPQA,
                  HumanEval (pass@1 with python3 sandbox), BBH, IFEval (25
                  verifiable constraints), AlpacaEval, AGIEval, HellaSwag,
                  ARC (Easy + Challenge), TruthfulQA (MC1+MC2), BoolQ,
                  GSM8K, MATH (boxed-answer equivalence), Winogrande. Real
                  questions in BuiltinSamples. EvalRunner emits joules-per-
                  correct alongside accuracy. 49 tests.

Quality:
- cargo check across all three workspaces: clean
- cargo clippy --all-targets -- -D warnings on every new crate: clean
- 374 new tests, all passing
- #![forbid(unsafe_code)] across every new crate
- No unwrap/expect outside #[cfg(test)]

Rust 1.95.0 edition 2024 (inherited via root rust-toolchain.toml).
2026-05-24 01:09:35 -04:00

246 lines
7.5 KiB
Rust

//! End-to-end issue / present / verify integration tests.
use std::collections::BTreeMap;
use std::sync::Arc;
use chrono::{TimeZone, Utc};
use ciborium::value::Value as CborValue;
use smart_byte_mdl::{
FixedTime, Issuer, IssuerKey, ItemsRequest, MobileDoc, NS_MDL,
P256DeviceSigner, SessionTranscript, TrustAnchor, ValidityInfo, Verifier,
present,
};
fn build_validity() -> ValidityInfo {
ValidityInfo {
signed: Utc.with_ymd_and_hms(2026, 1, 1, 0, 0, 0).unwrap(),
valid_from: Utc.with_ymd_and_hms(2026, 1, 1, 0, 0, 0).unwrap(),
valid_until: Utc.with_ymd_and_hms(2030, 1, 1, 0, 0, 0).unwrap(),
expected_update: None,
}
}
fn build_claims() -> BTreeMap<String, BTreeMap<String, CborValue>> {
let mut ns: BTreeMap<String, BTreeMap<String, CborValue>> = BTreeMap::new();
let mut inner: BTreeMap<String, CborValue> = BTreeMap::new();
inner.insert("family_name".into(), CborValue::Text("Doe".into()));
inner.insert("given_name".into(), CborValue::Text("Jane".into()));
inner.insert("birth_date".into(), CborValue::Text("1990-04-12".into()));
inner.insert("age_over_21".into(), CborValue::Bool(true));
inner.insert("document_number".into(), CborValue::Text("Z-1234".into()));
ns.insert(NS_MDL.into(), inner);
ns
}
struct Setup {
issuer_key: IssuerKey,
device_key: IssuerKey,
doc: MobileDoc,
}
fn issue() -> Setup {
let issuer_key = IssuerKey::generate_es256();
let device_key = IssuerKey::generate_es256();
let issuer = Issuer::new(
IssuerKey {
alg: issuer_key.alg,
p256: issuer_key.p256.clone(),
},
Vec::new(),
build_validity(),
);
let doc = issuer
.issue(
"org.iso.18013.5.1.mDL",
build_claims(),
device_key.cose_public_key(),
b"integration-seed",
)
.unwrap();
Setup {
issuer_key,
device_key,
doc,
}
}
#[test]
fn issue_verify_full_disclosure() {
let setup = issue();
let anchor = TrustAnchor::es256(setup.issuer_key.p256.verifying_key(), None);
let verifier = Verifier::new(
vec![anchor],
Arc::new(FixedTime(
Utc.with_ymd_and_hms(2027, 1, 1, 0, 0, 0).unwrap(),
)),
);
let claims = verifier.verify(&setup.doc).unwrap();
assert_eq!(claims.doc_type, "org.iso.18013.5.1.mDL");
let ns = &claims.claims[NS_MDL];
assert_eq!(ns["family_name"], CborValue::Text("Doe".into()));
assert_eq!(ns["given_name"], CborValue::Text("Jane".into()));
assert_eq!(ns["age_over_21"], CborValue::Bool(true));
assert_eq!(ns.len(), 5);
}
#[test]
fn selective_disclosure_reveals_only_requested_items() {
let setup = issue();
let signer = P256DeviceSigner {
key: setup.device_key.p256.clone(),
};
let transcript =
SessionTranscript::for_oid4vp("client-id", "https://verifier", "n", "m");
let mut req: BTreeMap<String, Vec<String>> = BTreeMap::new();
req.insert(
NS_MDL.into(),
vec!["family_name".into(), "age_over_21".into()],
);
let presented = present(
&setup.doc,
&req,
&signer,
&transcript,
BTreeMap::new(),
)
.unwrap();
let anchor = TrustAnchor::es256(setup.issuer_key.p256.verifying_key(), None);
let verifier = Verifier::new(
vec![anchor],
Arc::new(FixedTime(
Utc.with_ymd_and_hms(2027, 1, 1, 0, 0, 0).unwrap(),
)),
)
.with_transcript(transcript);
let claims = verifier.verify(&presented).unwrap();
let ns = &claims.claims[NS_MDL];
assert_eq!(ns.len(), 2);
assert!(ns.contains_key("family_name"));
assert!(ns.contains_key("age_over_21"));
assert!(!ns.contains_key("birth_date"));
assert!(!ns.contains_key("document_number"));
assert!(!ns.contains_key("given_name"));
}
#[test]
fn tampered_issuer_signed_item_is_rejected() {
let mut setup = issue();
let items = setup
.doc
.issuer_signed
.name_spaces
.get_mut(NS_MDL)
.unwrap();
for it in items.iter_mut() {
if it.element_identifier == "family_name" {
it.element_value = CborValue::Text("Mallory".into());
break;
}
}
let anchor = TrustAnchor::es256(setup.issuer_key.p256.verifying_key(), None);
let verifier = Verifier::new(
vec![anchor],
Arc::new(FixedTime(
Utc.with_ymd_and_hms(2027, 1, 1, 0, 0, 0).unwrap(),
)),
);
let err = verifier.verify(&setup.doc).unwrap_err();
assert!(
matches!(err, smart_byte_mdl::MdlError::DigestMismatch { .. }),
"got {err:?}"
);
}
#[test]
fn expired_validity_info_is_rejected() {
let setup = issue();
let anchor = TrustAnchor::es256(setup.issuer_key.p256.verifying_key(), None);
// 2031 is after validUntil 2030.
let verifier = Verifier::new(
vec![anchor],
Arc::new(FixedTime(
Utc.with_ymd_and_hms(2031, 1, 1, 0, 0, 0).unwrap(),
)),
);
let err = verifier.verify(&setup.doc).unwrap_err();
assert!(
matches!(err, smart_byte_mdl::MdlError::ValidityOutOfRange { .. }),
"got {err:?}"
);
}
#[test]
fn device_signed_with_wrong_key_is_rejected() {
let setup = issue();
// Sign with a wrong device key — the MSO commits to the original.
let wrong_device = IssuerKey::generate_es256();
let signer = P256DeviceSigner {
key: wrong_device.p256,
};
let transcript =
SessionTranscript::for_oid4vp("client-id", "https://verifier", "n", "m");
let mut req: BTreeMap<String, Vec<String>> = BTreeMap::new();
req.insert(NS_MDL.into(), vec!["family_name".into()]);
let presented = present(
&setup.doc,
&req,
&signer,
&transcript,
BTreeMap::new(),
)
.unwrap();
let anchor = TrustAnchor::es256(setup.issuer_key.p256.verifying_key(), None);
let verifier = Verifier::new(
vec![anchor],
Arc::new(FixedTime(
Utc.with_ymd_and_hms(2027, 1, 1, 0, 0, 0).unwrap(),
)),
)
.with_transcript(transcript);
let err = verifier.verify(&presented).unwrap_err();
assert!(
matches!(err, smart_byte_mdl::MdlError::Signature(_)),
"got {err:?}"
);
}
#[test]
fn items_request_drives_disclosure() {
let setup = issue();
let mut ns: BTreeMap<String, BTreeMap<String, bool>> = BTreeMap::new();
let mut inner: BTreeMap<String, bool> = BTreeMap::new();
inner.insert("family_name".into(), false);
inner.insert("age_over_21".into(), false);
ns.insert(NS_MDL.into(), inner);
let req = ItemsRequest {
doc_type: "org.iso.18013.5.1.mDL".into(),
name_spaces: ns,
};
let signer = P256DeviceSigner {
key: setup.device_key.p256,
};
let transcript =
SessionTranscript::for_oid4vp("client-id", "https://verifier", "n", "m");
let presented = present(
&setup.doc,
&req.requested(),
&signer,
&transcript,
BTreeMap::new(),
)
.unwrap();
let anchor = TrustAnchor::es256(setup.issuer_key.p256.verifying_key(), None);
let verifier = Verifier::new(
vec![anchor],
Arc::new(FixedTime(
Utc.with_ymd_and_hms(2027, 1, 1, 0, 0, 0).unwrap(),
)),
)
.with_transcript(transcript);
let claims = verifier.verify(&presented).unwrap();
let ns = &claims.claims[NS_MDL];
assert_eq!(ns.len(), 2);
assert!(ns.contains_key("family_name"));
assert!(ns.contains_key("age_over_21"));
}