From c665850ccbaa8827ea4521b4df2f695af9dacaf1 Mon Sep 17 00:00:00 2001 From: Transaction Science Date: Sat, 1 Aug 2026 23:23:47 -0400 Subject: [PATCH] wai-rs: prove the reconstruction binding over a REAL jpegai decode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reconstruction_binding unit tests bind over synthetic RGB. This closes the loop end to end: the byte-exact decoder decodes test256 to pixels, and the C2PA/JPEG-Trust hard binding is taken over those pixels — sha256 over the canonical RGB8, plus the descriptor pinning the reproducible decode. It exercises the property the capability rests on and that neural-coded media could not have before a byte-exact decode: the decode is deterministic (decode-equivalence), so the binding taken over one decode verifies a second decode byte-for-byte, while a single flipped pixel breaks it. Emits the actual assertion (label science.transaction.wai.hash.reconstruction) over the real decoded image. Also the first test that compiles `neural_int` + `provenance` together. Gated on the model bundle; skips cleanly without it. Co-Authored-By: Claude Opus 4.8 --- .../tests/jpegai_reconstruction_binding.rs | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 wai/wai-rs/tests/jpegai_reconstruction_binding.rs diff --git a/wai/wai-rs/tests/jpegai_reconstruction_binding.rs b/wai/wai-rs/tests/jpegai_reconstruction_binding.rs new file mode 100644 index 000000000..011839daa --- /dev/null +++ b/wai/wai-rs/tests/jpegai_reconstruction_binding.rs @@ -0,0 +1,96 @@ +//! End-to-end: a **real** byte-exact JPEG-AI decode → a reproducible-reconstruction +//! binding over the decoded pixels. The [`wai::reconstruction_binding`] unit tests cover +//! the binding on synthetic RGB; this closes the loop on real content — the byte-exact +//! decoder produces the pixels, and the C2PA/JPEG-Trust hard binding is taken over them. +//! +//! It exercises the property the whole capability rests on: the decode is deterministic +//! (`decode-equivalence`), so the binding taken over one decode verifies any faithful +//! reproduction, and a single flipped pixel breaks it. That is exactly what a hard +//! binding over neural-coded media could not do before a byte-exact decode existed. +//! +//! env: WAI_JPEGAI_CODESTREAM, WAI_JPEGAI_WEIGHTS_DIR, WAI_JPEGAI_NORM +//! (the bundle from `tools/wai_jpegai_build_e2e_inputs.py`; see jpegai_e2e_full). +#![cfg(all(feature = "neural_int", feature = "provenance"))] + +use wai::jpegai_decode::{decode, DecoderWeights, NormTables, PlaneWeights}; +use wai::jpegai_icci::IcciNet; +use wai::jpegai_synthesis::{IntNet, Weights}; +use wai::reconstruction_binding::{ReconstructionBinding, ReconstructionDescriptor}; + +fn jload(p: &std::path::Path) -> serde_json::Value { + serde_json::from_slice(&std::fs::read(p).unwrap()).unwrap() +} + +#[test] +fn real_decode_to_reconstruction_binding() { + let (Ok(cs), Ok(dir), Ok(nf)) = ( + std::env::var("WAI_JPEGAI_CODESTREAM"), + std::env::var("WAI_JPEGAI_WEIGHTS_DIR"), + std::env::var("WAI_JPEGAI_NORM"), + ) else { + eprintln!("skip: set WAI_JPEGAI_CODESTREAM + WAI_JPEGAI_WEIGHTS_DIR + WAI_JPEGAI_NORM"); + return; + }; + let Ok(data) = std::fs::read(&cs) else { eprintln!("skip: no codestream"); return }; + + // --- load the model bundle (same shape as jpegai_e2e_full) --- + let dpath = std::path::Path::new(&dir); + let w = |n: &str| Weights::from_json(&jload(&dpath.join(n))); + let net = |n: &str| IntNet::from_json(&jload(&dpath.join(n))); + let weights = DecoderWeights { + luma: PlaneWeights { hyper_scale: net("hs_y.json"), hyper_decoder: w("hyp_y.json"), synthesis: w("synth_y.json") }, + chroma: PlaneWeights { hyper_scale: net("hs_uv.json"), hyper_decoder: w("hyp_uv.json"), synthesis: w("synth_uv.json") }, + mcm_y: [w("mcm0_y.json"), w("mcm1_y.json"), w("mcm2_y.json"), w("mcm3_y.json")], + icci: IcciNet::from_json(&jload(&dpath.join("icci.json"))), + }; + let nv = jload(std::path::Path::new(&nf)); + let i64v = |k: &str| nv[k].as_array().unwrap().iter().map(|x| x.as_i64().unwrap()).collect::>(); + let u8v = |k: &str| nv[k].as_array().unwrap().iter().map(|x| x.as_u64().unwrap() as u8).collect::>(); + let i32v = |k: &str| nv[k].as_array().unwrap().iter().map(|x| x.as_i64().unwrap() as i32).collect::>(); + let i3 = |k: &str| { let a = nv[k].as_array().unwrap(); [a[0].as_i64().unwrap(), a[1].as_i64().unwrap(), a[2].as_i64().unwrap()] }; + let f3 = |k: &str| { let a = nv[k].as_array().unwrap(); [a[0].as_f64().unwrap() as f32, a[1].as_f64().unwrap() as f32, a[2].as_f64().unwrap() as f32] }; + let norm = NormTables { + pmf: nv["pmf"].as_array().unwrap().iter() + .map(|r| r.as_array().unwrap().iter().map(|x| x.as_i64().unwrap()).collect()).collect(), + bounds: u8v("bounds"), per_channel: nv["per_channel"].as_u64().unwrap() as usize, + cdfs_y: u8v("cdfs_y"), cdfs_uv: u8v("cdfs_uv"), gain_y: i64v("gain_y"), gain_uv: i64v("gain_uv"), + lsbs_t0: i32v("lsbs_t0"), lsbs_t1: i32v("lsbs_t1"), lef_thr: i3("lef_thr0"), lef_mag: f3("lef_mag0"), + }; + + // --- decode the real codestream → RGB, then bind over the decoded pixels --- + let img = decode(&data, &weights, &norm).expect("supported geometry"); + assert_eq!((img.h, img.w), (256, 256)); + assert_eq!(img.data.len(), 256 * 256 * 3); + + let desc = ReconstructionDescriptor { + decoder_id: 0, // WAI pins one synthesis branch + profile: "tools_0".into(), + level: "L1".into(), + width: img.w as u32, + height: img.h as u32, + format: "RGB8".into(), + color_space: "bt709".into(), + }; + let binding = ReconstructionBinding::bind(&img.data, desc.clone()); + assert_eq!(binding.alg, "sha256"); + assert_eq!(binding.hash_hex().len(), 64); + + // The binding verifies its own decoded pixels. + assert!(binding.verify(&img.data), "the binding must verify the pixels it was taken over"); + + // decode-equivalence: a second decode is byte-identical, and the binding — taken + // over the first — verifies the second. That is the portable-hard-binding property. + let img2 = decode(&data, &weights, &norm).expect("supported geometry"); + assert_eq!(img2.data, img.data, "the decode is deterministic (decode-equivalence)"); + assert!(binding.verify(&img2.data), "the binding verifies any faithful reproduction"); + + // A single flipped pixel breaks the hard binding. + let mut tampered = img.data.clone(); + tampered[12_345] ^= 1; + assert!(!binding.verify(&tampered), "a single flipped byte must fail the binding"); + + eprintln!("reconstruction binding over the real JPEG-AI decode:"); + eprintln!(" assertion = {}", ReconstructionBinding::C2PA_LABEL); + eprintln!(" sha256 = {}", binding.hash_hex()); + eprintln!(" json = {}", binding.to_json()); +} -- 2.54.0 (Apple Git-157)