//! `wai.live.coperformance` (extensions/co-performance.md): the committed corpus //! `live-conformance/coperformance/` regenerates byte for byte from its fixed seeds, holds no //! other file, every room in it gets the outcome it states, and the extension's §10 lists //! exactly the reasons the reference reports. The generator itself asserts that the corpus //! gives every one of them. #![cfg(feature = "co_performance")] use std::collections::BTreeMap; use std::path::PathBuf; use wai::co_performance::{corpus, Reason}; fn wai_dir() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..") } fn committed() -> BTreeMap { let dir = wai_dir().join("live-conformance/coperformance"); std::fs::read_dir(&dir) .expect("the committed corpus") .flatten() .map(|e| (e.file_name().to_string_lossy().into_owned(), e.path())) .filter(|(n, _)| n != "README.md") .map(|(n, p)| (n, std::fs::read_to_string(p).expect("a text file"))) .collect() } #[test] fn the_committed_corpus_regenerates_from_its_seeds() { let files = committed(); let generated: BTreeMap = corpus::generate().into_iter().collect(); let extra: Vec<&String> = files.keys().filter(|k| !generated.contains_key(*k)).collect(); let missing: Vec<&String> = generated.keys().filter(|k| !files.contains_key(*k)).collect(); let differ: Vec<&String> = generated.iter().filter(|(k, v)| files.get(*k).is_some_and(|f| f != *v)).map(|(k, _)| k).collect(); assert!(extra.is_empty() && missing.is_empty() && differ.is_empty(), "extra {extra:?}, missing {missing:?}, differ {differ:?}: run `wai_co_performance_vectors gen`"); } #[test] fn every_room_gets_its_stated_outcome() { let fails = corpus::verify(&committed()); assert!(fails.is_empty(), "{}", fails.join("\n")); } /// §10 of the extension lists exactly the codes `Reason::ALL` has, each once, in order. #[test] fn the_extension_lists_the_reasons() { let text = std::fs::read_to_string(wai_dir().join("extensions/co-performance.md")).expect("the extension"); let at = text.find("\n## 10. Reasons").expect("a §10"); let end = text[at + 1..].find("\n## ").map_or(text.len(), |e| at + 1 + e); let listed: Vec = text[at..end].lines().filter(|l| l.starts_with("| `")).filter_map(|l| l.split('`').nth(1).map(String::from)).collect(); let want: Vec = Reason::ALL.iter().map(|r| r.code().to_string()).collect(); assert_eq!(listed, want, "§10's table and Reason::ALL differ"); } fn unhex(s: &str) -> Vec { (0..s.len()).step_by(2).map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("hexadecimal")).collect() } fn d32(s: &str) -> [u8; 32] { unhex(s).try_into().expect("32 bytes") } /// A corpus room's inputs, read. struct Room { descriptor: Vec, grants: Vec>, chains: Vec>>, policies: Vec>, objects: Vec, payloads: Vec>, } fn room(name: &str) -> Room { let files = committed(); let doc: serde_json::Value = serde_json::from_str(&files["vectors.json"]).expect("JSON"); let v = doc["vectors"].as_array().unwrap().iter().find(|v| v["name"] == name).expect("the room"); let list = |v: &serde_json::Value| v.as_array().unwrap().iter().map(|h| unhex(h.as_str().unwrap())).collect::>(); Room { descriptor: unhex(v["descriptor"].as_str().unwrap()), grants: list(&v["grants"]), chains: v["chains"].as_array().unwrap().iter().map(list).collect(), policies: list(&v["policies"]), objects: v["objects"] .as_array() .unwrap() .iter() .map(|o| wai::co_performance::Object { principal: d32(o["principal"].as_str().unwrap()), track: d32(o["track"].as_str().unwrap()), group: o["group"].as_u64().unwrap(), object: o["object"].as_u64().unwrap(), digest: d32(o["digest"].as_str().unwrap()), arrival: o["arrival"].as_u64().unwrap(), due: o["due"].as_u64().unwrap(), }) .collect(), payloads: list(&v["payloads"]), } } /// What a room clock signs, read from the room replayed up to each statement only a room key /// signs (co-performance §8), is that statement byte for byte: every commitment, selection and /// fidelity statement of the corpus's accepted rooms, recomputed from the room as it stood just /// before it; and every object's marks are the flags the replay gives it. #[test] fn the_clock_signs_what_the_verifier_recomputes() { use wai::co_performance::{magic, replay, Input, Statement}; use wai::live_events::{kind, Event}; let mut checked = BTreeMap::::new(); for name in ["jam", "audience"] { let r = room(name); let d = wai::live_room::Descriptor::parse(&r.descriptor).unwrap(); for (c, chain) in r.chains.iter().enumerate() { for (i, rec) in chain.iter().enumerate() { let ev = Event::parse(rec).unwrap(); if ev.kind != kind::META || !d.is_room_key(&ev.principal) || ev.payload.len() < 4 { continue; } let m: [u8; 4] = ev.payload[..4].try_into().unwrap(); if ![magic::COMMIT, magic::SELECTION, magic::FIDELITY].contains(&m) { continue; } let mut before = r.chains.clone(); before[c].truncate(i); let inp = Input { descriptor: &r.descriptor, grants: &r.grants, head: None, chains: &before, policies: &r.policies, objects: &r.objects, payloads: &r.payloads }; let rp = replay(&inp).unwrap_or_else(|e| panic!("{name}: the room before record {i} of chain {c} replays: {e:?}")); let signed = Statement::parse(&ev.payload).unwrap(); let made = match &signed { Statement::Commit(x) => Statement::Commit(rp.commitment(&x.window, ev.t).expect("a commitment")), Statement::Selection(x) => Statement::Selection(rp.selection(&x.window, x.seed).expect("a selection")), Statement::Fidelity(x) => Statement::Fidelity(rp.fidelity(x.through, ev.t).expect("a fidelity statement")), _ => unreachable!("filtered above"), }; assert_eq!(made.encode(), ev.payload, "{name}: chain {c} record {i}"); *checked.entry(String::from_utf8(m.to_vec()).unwrap()).or_default() += 1; // Once signed, the clock does not sign it again. if let Statement::Commit(x) = &signed { let rp = replay(&Input { chains: &r.chains, ..inp }).unwrap(); assert!(rp.commitment(&x.window, ev.t).is_none(), "{name}: a window committed is not committed again"); assert!(rp.windows().iter().any(|w| w.digest == x.window && w.commit.is_some() && w.selected)); } } } // Every object's marks are the flags the whole room's replay gives it. let inp = Input { descriptor: &r.descriptor, grants: &r.grants, head: None, chains: &r.chains, policies: &r.policies, objects: &r.objects, payloads: &r.payloads }; let rp = replay(&inp).unwrap(); let mut marked = BTreeMap::<([u8; 32], u64, u64), u8>::new(); for rec in r.chains.iter().flatten() { let ev = Event::parse(rec).unwrap(); if ev.kind == kind::META && ev.payload.starts_with(&magic::MARK) { let Statement::Mark(x) = Statement::parse(&ev.payload).unwrap() else { unreachable!() }; *marked.entry((x.track, x.group, x.object)).or_default() |= x.flags; } } for o in &r.objects { assert_eq!(rp.marks_for(o), marked.get(&(o.track, o.group, o.object)).copied().unwrap_or(0), "{name}: the marks of object {}/{}", o.group, o.object); } *checked.entry("objects".into()).or_default() += r.objects.len(); } assert!(checked.get("WPK1").copied().unwrap_or(0) >= 3 && checked.get("WPS1").copied().unwrap_or(0) >= 3 && checked.get("WPF1").copied().unwrap_or(0) >= 1, "{checked:?}"); assert!(room("jam").objects.iter().any(|o| { let r = room("jam"); let inp = Input { descriptor: &r.descriptor, grants: &r.grants, head: None, chains: &r.chains, policies: &r.policies, objects: &r.objects, payloads: &r.payloads }; replay(&inp).unwrap().marks_for(o) != 0 }), "the jam room has an object to mark"); } /// A draw's selection is refused a seed that is not the one committed to, and a commitment is /// not made before its window closes. #[test] fn the_clock_keeps_to_the_commitment_and_the_seed() { use wai::co_performance::{replay, rule, Input}; let r = room("audience"); let inp = Input { descriptor: &r.descriptor, grants: &r.grants, head: None, chains: &r.chains, policies: &r.policies, objects: &r.objects, payloads: &r.payloads }; let rp = replay(&inp).unwrap(); let ws = rp.windows(); let draw = ws.iter().find(|w| w.window.rule == rule::DRAW).expect("a draw"); assert!(rp.selection(&draw.digest, [0xee; 32]).is_none(), "a seed not committed to"); // The room without its clock's statements after the draw opened: no commitment before close. let mut cut = r.chains.clone(); let d = wai::live_room::Descriptor::parse(&r.descriptor).unwrap(); for c in cut.iter_mut() { if c.first().is_some_and(|x| d.is_room_key(&wai::live_events::Event::parse(x).unwrap().principal)) { c.retain(|x| wai::live_events::Event::parse(x).unwrap().t <= draw.opened); } } let rp = replay(&Input { chains: &cut, ..inp }).unwrap(); assert!(rp.commitment(&draw.digest, draw.window.close - 1).is_none(), "commit_early"); assert!(rp.commitment(&draw.digest, draw.window.close).is_some()); assert!(rp.selection(&draw.digest, [0; 32]).is_none(), "no selection before a commitment"); }