Some checks failed
joule-moq-remote host agent / joule-moq-remote · does this change touch it (pull_request) Successful in 5s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 7s
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 7s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 7s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 5s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (pull_request) Successful in 47s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 40s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m53s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 5m11s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 12m28s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 12m24s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 56s
wai-audit collector and player integration / does this change touch it (pull_request) Successful in 42s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (pull_request) Successful in 28s
WAI operation catalogue / does this change touch it (pull_request) Successful in 22s
WAI conformance / does this change touch it (pull_request) Successful in 28s
WAI energy receipts / does this change touch it (pull_request) Successful in 26s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 36s
wai-fleet service / does this change touch it (pull_request) Successful in 36s
WAI HTTP delivery / WAI HTTP · does this change touch it (pull_request) Successful in 30s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Has been skipped
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Has been skipped
wai-key-proxy / does this change touch it (pull_request) Successful in 29s
wai-ledger service / does this change touch it (pull_request) Successful in 37s
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Successful in 35s
wai-quantum docs, course and locales / does this change touch it (pull_request) Successful in 37s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 38s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 30s
wai-quantum for JavaScript / does this change touch it (pull_request) Successful in 32s
WAI conformance / fast integer kernels, every x86_64 kernel set (AVX-512 silicon) (pull_request) Successful in 3m4s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 6m25s
wai-sink-android native sink library / does this change touch it (pull_request) Successful in 35s
wai-sink-swift native sink package / does this change touch it (pull_request) Successful in 36s
WAI Studio / does this change touch it (pull_request) Successful in 24s
wai-web wasm32 / does this change touch it (pull_request) Successful in 26s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 2m47s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 6m11s
wai-quantum studio and desktop / desktop app · windows (pull_request) Successful in 9m54s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (pull_request) Successful in 1m25s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 5m49s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 20s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 51s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 13m11s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 7m48s
wai-fleet service / service · macos (pull_request) Successful in 37s
wai-ledger service / service · macos (pull_request) Successful in 47s
wai-pack / wai-pack · macos (pull_request) Successful in 2m24s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 3m37s
wai-audit collector and player integration / collector · linux (pull_request) Successful in 1m16s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 8m2s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (pull_request) Successful in 1m28s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (pull_request) Successful in 2m26s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (pull_request) Successful in 5m16s
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (pull_request) Successful in 1m41s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 30s
WAI operation catalogue / the catalogue and every door · linux (pull_request) Successful in 4m51s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 3m20s
wai-fleet service / service · linux (pull_request) Successful in 1m45s
wai-key-proxy / proxy · linux (pull_request) Successful in 1m4s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 18m45s
wai-ledger service / service · linux (pull_request) Successful in 1m46s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (pull_request) Successful in 11m5s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 3m19s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Failing after 12m57s
wai-quantum docs, course and locales / the course and the command line's languages · linux (pull_request) Successful in 2m7s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (pull_request) Successful in 8s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 10m28s
wai-pack / wai-pack · linux (pull_request) Successful in 2m4s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 17m14s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (pull_request) Failing after 17s
wai-quantum for JavaScript / javascript · linux (pull_request) Successful in 3m7s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 3m53s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 14m53s
wai-quantum studio and desktop / desktop app · linux (pull_request) Successful in 5m41s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 5m16s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (pull_request) Successful in 17m7s
WAI Studio / Studio in WebKit · linux (pull_request) Failing after 10m52s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Has been cancelled
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Has been cancelled
wai-pack / wai-pack · linux-arm64 (pull_request) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (pull_request) Has been cancelled
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (pull_request) Has been cancelled
The catalogue lists what works, and the toolchain could verify an upscale record and a rendition record without any door that made one. The doing lived in a hosted service's providers, which is the wrong side of the line: WAI holds every open ability. `wai upscale run` and `wai tonemap run` make the picture and, with `--record`, sign the record. `wai upscale verify` and `wai tonemap verify` recompute that record under require-proof from what it names, and hold the output to it. `exact_upscale::make` and `exact_tonemap::make` are the functions under them, and they return the record's body for a caller to sign, so a service that signs with its own key can use them too. The commands are `run` and `verify` because the catalogue refuses a command that is the start of another: `wai upscale` beside `wai upscale verify` is a form that can never be told apart from a file named verify. Co-Authored-By: Claude Opus 5.5 <[email protected]>
150 lines
8.8 KiB
Rust
150 lines
8.8 KiB
Rust
//! `wai upscale` and `wai tonemap` end to end: what each runs and writes is what its extension's verifier
|
|
//! proves under `require-proof`, from the files it wrote alone.
|
|
#![cfg(all(feature = "exact_upscale", feature = "exact_tonemap"))]
|
|
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::{Command, Output};
|
|
|
|
use wai::exact_tonemap as tm;
|
|
use wai::exact_upscale as ex;
|
|
|
|
const SEED: &str = "0707070707070707070707070707070707070707070707070707070707070707";
|
|
|
|
fn wai_in(d: &Path, args: &[&str]) -> Output {
|
|
Command::new(env!("CARGO_BIN_EXE_wai")).current_dir(d).args(args).output().expect("wai runs")
|
|
}
|
|
|
|
fn scratch(name: &str) -> PathBuf {
|
|
let d = std::env::temp_dir().join(format!("wai-cli-derive-{name}-{}", std::process::id()));
|
|
let _ = std::fs::remove_dir_all(&d);
|
|
std::fs::create_dir_all(&d).unwrap();
|
|
d
|
|
}
|
|
|
|
fn ok(o: &Output) -> &Output {
|
|
assert!(o.status.success(), "{}{}", String::from_utf8_lossy(&o.stdout), String::from_utf8_lossy(&o.stderr));
|
|
o
|
|
}
|
|
|
|
fn prior_path() -> String {
|
|
Path::new(env!("CARGO_MANIFEST_DIR")).join("../live-conformance/upscale/priors/generic.wsr").to_str().unwrap().to_string()
|
|
}
|
|
|
|
#[test]
|
|
fn an_upscale_writes_what_exact_upscale_proves() {
|
|
let d = scratch("upscale");
|
|
let rgb: Vec<u8> = (0..8u32 * 6).flat_map(|i| [(i * 7 % 256) as u8, (i * 3 % 256) as u8, (i % 256) as u8]).collect();
|
|
std::fs::write(d.join("in.png"), wai::png_still::encode(&rgb, 8, 6)).unwrap();
|
|
let prior = prior_path();
|
|
let o = wai_in(&d, &["upscale", "run", "in.png", "--prior", &prior, "-o", "out.png", "--record", "r.json", "--envelope", "in.wai", "--key", SEED, "--json"]);
|
|
let v: serde_json::Value = serde_json::from_slice(&ok(&o).stdout).unwrap();
|
|
let v = &v["data"];
|
|
assert_eq!((&v["width"], &v["height"], &v["subpixels"]), (&serde_json::json!(16), &serde_json::json!(12), &serde_json::json!(16 * 12 * 3)));
|
|
|
|
let text = std::fs::read_to_string(d.join("r.json")).unwrap();
|
|
let envelope = std::fs::read(d.join("in.wai")).unwrap();
|
|
let (pw, ph, samples) = wai::png_still::decode(&std::fs::read(d.join("out.png")).unwrap()).unwrap();
|
|
assert_eq!((pw, ph), (16, 12));
|
|
let u = ex::read_upscale(&text).unwrap();
|
|
use sha2::{Digest, Sha256};
|
|
assert_eq!(Sha256::digest(&samples).as_slice(), u.output, "the picture is the record's output");
|
|
let case = |priors: Vec<Vec<u8>>| ex::Case {
|
|
upscales: vec![text.clone()],
|
|
objects: vec![envelope.clone()],
|
|
decoded: vec![(wai::jwp_hash::content_hash(&envelope), rgb.clone())],
|
|
priors,
|
|
policy: ex::Policy { require_proof: true, ..Default::default() },
|
|
..Default::default()
|
|
};
|
|
assert!(matches!(ex::verify(&case(vec![std::fs::read(&prior).unwrap()])), ex::Outcome::Accept(_)));
|
|
assert!(!matches!(ex::verify(&case(vec![])), ex::Outcome::Accept(_)), "with no prior, nothing is proved");
|
|
|
|
// `wai upscale verify` holds what it wrote, and refuses what it did not.
|
|
let verify = |d: &Path, args: &[&str]| -> (bool, serde_json::Value) {
|
|
let o = wai_in(d, &[&["upscale", "verify", "r.json", "--envelope", "in.wai"], args].concat());
|
|
(o.status.success(), serde_json::from_slice(&o.stdout).unwrap_or(serde_json::Value::Null))
|
|
};
|
|
let (good, v) = verify(&d, &["--prior", &prior, "--picture", "out.png"]);
|
|
assert!(good, "{v}");
|
|
assert_eq!((&v["outcome"], &v["subpixels"]), (&serde_json::json!("accept"), &serde_json::json!(16 * 12 * 3)));
|
|
let mut other = samples.clone();
|
|
other[0] ^= 1;
|
|
std::fs::write(d.join("other.png"), wai::png_still::encode(&other, 16, 12)).unwrap();
|
|
let (good, v) = verify(&d, &["--prior", &prior, "--picture", "other.png"]);
|
|
assert!(!good && v["reason"] == "picture_mismatch", "{v}");
|
|
let title = Path::new(env!("CARGO_MANIFEST_DIR")).join("../live-conformance/upscale/priors/title.wsr");
|
|
let (good, v) = verify(&d, &["--prior", title.to_str().unwrap()]);
|
|
assert!(!good && v["reason"] == "upscale_not_proved", "another prior proves nothing: {v}");
|
|
|
|
// The picture alone needs no key; a record does, and names the envelope.
|
|
ok(&wai_in(&d, &["upscale", "run", "in.png", "--prior", &prior, "-o", "bare.png"]));
|
|
assert_eq!(std::fs::read(d.join("bare.png")).unwrap(), std::fs::read(d.join("out.png")).unwrap(), "the derivation is exact");
|
|
assert!(!wai_in(&d, &["upscale", "run", "in.png", "--prior", &prior, "-o", "x.png", "--record", "x.json", "--envelope", "x.wai"]).status.success(), "a record needs a key");
|
|
assert!(!wai_in(&d, &["upscale", "run", "in.png", "--prior", &prior, "-o", "x.png", "--record", "x.json", "--key", SEED]).status.success(), "a record needs its envelope");
|
|
assert!(!wai_in(&d, &["upscale", "run", "in.png", "--prior", &prior, "-o", "x.png", "--derivation", "sr3"]).status.success());
|
|
std::fs::write(d.join("grey.png"), wai::png_still::encode_grey(&[9u8; 48], 8, 6)).unwrap();
|
|
assert!(!wai_in(&d, &["upscale", "run", "grey.png", "--prior", &prior, "-o", "x.png"]).status.success(), "the reader holds 8-bit RGB");
|
|
}
|
|
|
|
fn hdr_envelope(w: u32, h: u32) -> Vec<u8> {
|
|
use wai::container::{Rendition, WaiMulti};
|
|
let e = tm::corpus::encode(&tm::corpus::scene(0, w, h), w, h, 4, false, (1, 1), false);
|
|
let companion = tm::wgm1(&e.metadata.to_bytes(), &wai::png_still::encode_grey(&e.map, e.map_w, e.map_h));
|
|
WaiMulti::new(
|
|
"image",
|
|
"replicate",
|
|
serde_json::Value::Null,
|
|
vec![
|
|
Rendition::media(wai::codecs::CAP_IMAGE_PNG, "png", wai::png_still::encode(&e.base, w, h)).with_id("base").with_payload_digest(),
|
|
Rendition::companion(tm::CAP_GAINMAP, companion, wai::codecs::CAP_IMAGE_PNG).with_id("gainmap").with_companion_of_id("base").with_payload_digest(),
|
|
],
|
|
)
|
|
.to_bytes()
|
|
.unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn a_tone_mapping_writes_what_exact_tonemap_proves() {
|
|
let d = scratch("tonemap");
|
|
let envelope = hdr_envelope(16, 12);
|
|
std::fs::write(d.join("in.wai"), &envelope).unwrap();
|
|
let o = wai_in(&d, &["tonemap", "run", "in.wai", "--headrooms", "20000,10000", "--out", "r", "--record", "r.json", "--key", SEED, "--json"]);
|
|
let v: serde_json::Value = serde_json::from_slice(&ok(&o).stdout).unwrap();
|
|
assert_eq!(v["data"]["subpixels"], 2 * 16 * 12 * 3);
|
|
|
|
let text = std::fs::read_to_string(d.join("r.json")).unwrap();
|
|
let r = tm::read_record(&text).unwrap();
|
|
// Ascending by headroom, each file the bytes its picture states.
|
|
assert_eq!(r.pictures.iter().map(|p| p.headroom).collect::<Vec<_>>(), vec![10_000, 20_000]);
|
|
for p in &r.pictures {
|
|
let b = std::fs::read(d.join(format!("r/rendition-h{}.rgb16", p.headroom))).unwrap();
|
|
assert_eq!(tm::digest(&b), p.output, "headroom {}", p.headroom);
|
|
}
|
|
let mut held = tm::Held::default();
|
|
held.hold_envelope(envelope);
|
|
assert!(matches!(tm::verify(std::slice::from_ref(&text), &held, tm::Policy::RequireProof), tm::Outcome::Accept(_)));
|
|
assert!(!matches!(tm::verify(std::slice::from_ref(&text), &tm::Held::default(), tm::Policy::RequireProof), tm::Outcome::Accept(_)), "with no envelope, nothing is proved");
|
|
|
|
// `wai tonemap verify` holds what it wrote, and refuses what it did not.
|
|
let o = wai_in(&d, &["tonemap", "verify", "r.json", "--envelope", "in.wai", "--renditions", "r"]);
|
|
let v: serde_json::Value = serde_json::from_slice(&ok(&o).stdout).unwrap();
|
|
assert_eq!((&v["outcome"], &v["subpixels"]), (&serde_json::json!("accept"), &serde_json::json!(2 * 16 * 12 * 3)));
|
|
let path = d.join("r/rendition-h20000.rgb16");
|
|
let mut b = std::fs::read(&path).unwrap();
|
|
b[0] ^= 1;
|
|
std::fs::write(&path, b).unwrap();
|
|
let o = wai_in(&d, &["tonemap", "verify", "r.json", "--envelope", "in.wai", "--renditions", "r"]);
|
|
let v: serde_json::Value = serde_json::from_slice(&o.stdout).unwrap();
|
|
assert!(!o.status.success() && v["reason"] == "rendition_mismatch" && v["at"] == serde_json::json!(["renditions", 1]), "{v}");
|
|
std::fs::write(d.join("other.wai"), hdr_envelope(8, 6)).unwrap();
|
|
let o = wai_in(&d, &["tonemap", "verify", "r.json", "--envelope", "other.wai"]);
|
|
let v: serde_json::Value = serde_json::from_slice(&o.stdout).unwrap();
|
|
assert!(!o.status.success() && v["reason"] == "rendition_not_proved", "another envelope proves nothing: {v}");
|
|
|
|
assert!(!wai_in(&d, &["tonemap", "run", "in.wai", "--headrooms", "10,10", "--out", "x"]).status.success(), "headrooms are distinct");
|
|
assert!(!wai_in(&d, &["tonemap", "run", "in.wai", "--headrooms", "60001", "--out", "x"]).status.success(), "past the largest headroom");
|
|
assert!(!wai_in(&d, &["tonemap", "run", "in.wai", "--headrooms", "ten", "--out", "x"]).status.success());
|
|
assert!(!wai_in(&d, &["tonemap", "run", "in.wai", "--headrooms", "10", "--out", "x", "--input-class", "invented"]).status.success());
|
|
std::fs::write(d.join("one.wai"), b"WAI1 not this").unwrap();
|
|
assert!(!wai_in(&d, &["tonemap", "run", "one.wai", "--headrooms", "10", "--out", "x"]).status.success(), "a gain map needs a WAI2");
|
|
}
|