open-standards/wai/wai-rs/tests/co_performance.rs
Transaction Science f191f2b95a co-performance: the commitment's magic is WPK1, not WPC1 (taken by ad-presentation)
ad-presentation (on main) registers WPC1 for a player's presentation claim, and
co-performance registered WPC1 again for its commitment, so the registry's
library test (wire_identifiers_are_in_their_documents) refuses the train:
"WPC1 (magic) is listed twice". The commitment takes WPK1, unused anywhere:
the extension's magic table and §7.5 layout, wai-rs's constant, the relay's
floor reader, the independent verifier, the SPEC §5 paragraph, the changelog
entry and two comments. The corpus is regenerated by its generator (only the
commitments' bytes and what signs or digests them change) and the registry
export with it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 04:11:30 -04:00

191 lines
9.9 KiB
Rust

//! `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<String, String> {
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<String, String> = 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<String> =
text[at..end].lines().filter(|l| l.starts_with("| `")).filter_map(|l| l.split('`').nth(1).map(String::from)).collect();
let want: Vec<String> = 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<u8> {
(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<u8>,
grants: Vec<Vec<u8>>,
chains: Vec<Vec<Vec<u8>>>,
policies: Vec<Vec<u8>>,
objects: Vec<wai::co_performance::Object>,
payloads: Vec<Vec<u8>>,
}
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::<Vec<_>>();
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::<String, usize>::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");
}