open-standards/wai/wai-rs/tests/video_receipt.rs
Transaction Science 030d4aab85 wai: receipt decode refusals are codes; the Python decode allocates as it goes
- video_receipt::decode_wiv1 reports a decode refusal by its code
  (stream_exhausted, stream_noncanonical, field_range), as it already did
  for a parse refusal, not by a sentence.
- int_payload_verify.py grows each frame as its symbols decode instead of
  allocating it before the stream is read.
- The receipts workflow runs when the refusal fixtures its test reads
  change.

Test: video_receipt::decode_wiv1_reports_refusal_codes (the run-out and
unread-word fixtures, and a JSON form).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 21:15:43 -04:00

350 lines
15 KiB
Rust

//! `wai.video.int_motion` receipt — the metered leg of the integer video class.
//!
//! The point of these tests is the split the profile rests on: everything except
//! the energy is independently checkable from the codestream, and the energy is
//! attested by the signature alone. Each half is tested for what it actually
//! promises, and the tamper cases confirm the checkable half cannot be bent.
#![cfg(feature = "video_receipt")]
// Most tests here seal over the tool's JSON form through the deprecated entry points:
// they are the legacy receipts, whose pinned bytes must keep verifying. The tests of
// the WIV1 payload, the identity a receipt has now, are at the end.
#![allow(deprecated)]
use std::path::PathBuf;
use ed25519_dalek::SigningKey;
use wai::energy_class::{CounterFiltering, Uncertainty};
use wai::video_receipt::{work_pixel_ops, Provenance, VideoReceipt};
fn dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/vectors/int_video")
}
fn raw(name: &str) -> Vec<u8> {
std::fs::read(dir().join(name)).expect("read vector")
}
fn key(seed: u8) -> SigningKey {
SigningKey::from_bytes(&[seed; 32])
}
/// An on-chip counter reading as the native meter emits it: a declared 3 %
/// standard uncertainty over a 2.8 s bracket, filtering state not determinable
/// by an unprivileged reader.
fn chip() -> Provenance {
Provenance::on_chip_counter(Uncertainty::new(30_000, 2_800_000).unwrap(), CounterFiltering::Unknown)
.unwrap()
}
fn seal_as(name: &str, uj: u64, prov: Option<Provenance>) -> (VideoReceipt, Vec<u8>, serde_json::Value) {
let bytes = raw(name);
let bs: serde_json::Value = serde_json::from_slice(&bytes).expect("parse");
let r = VideoReceipt::seal_decode(&key(7), "did:example:meter", &bytes, &bs, uj, prov, None)
.expect("seal");
(r, bytes, bs)
}
fn seal(name: &str, uj: u64) -> (VideoReceipt, Vec<u8>, serde_json::Value) {
seal_as(name, uj, (uj > 0).then(chip))
}
#[test]
fn seals_and_verifies_against_the_committed_clip() {
let (r, bytes, bs) = seal("int_video_bitstream.json", 4_200);
assert!(r.verify(), "signature + internal consistency");
assert!(r.verify_reconstruction(&bytes, &bs), "re-decode must reproduce every frame");
// The work figure follows from the geometry and is recomputable, so it
// cannot be inflated to flatter an energy number.
assert_eq!(r.h, 48);
assert_eq!(r.w, 48);
assert_eq!(r.frames.len(), 5);
assert_eq!(r.work_pixel_ops, work_pixel_ops(5, 48, 48));
assert_eq!(r.work_pixel_ops, 5 * 48 * 48 * 3);
let (rate, prov) = r.uj_per_kilopixel_op().expect("metered");
assert!((rate - 4_200.0 * 1000.0 / 34_560.0).abs() < 1e-9);
assert_eq!(prov, chip());
}
/// An unmetered receipt reports **no** rate. A `0` would read as "this decode
/// was free", which is a stronger and false claim than "nobody measured".
#[test]
fn unmetered_reports_no_rate_rather_than_zero() {
let (r, _, _) = seal("int_video_bitstream.json", 0);
assert!(r.verify());
assert_eq!(r.joules_micro, 0);
assert!(r.uj_per_kilopixel_op().is_none());
assert_eq!(r.energy_provenance, None);
assert!(r.to_json().contains("\"uj_per_kilopixel_op\":null"));
assert!(r.to_json().contains("\"energy_provenance\":null"));
}
/// Real footage, the half-pel path — the clip whose decode is most at risk of
/// differing between architectures, and therefore the one whose receipt is
/// worth the most.
#[test]
fn real_footage_receipt_round_trips() {
let (r, bytes, bs) = seal("video_real_bitstream.json", 91_000);
assert!(r.verify());
assert!(r.verify_reconstruction(&bytes, &bs));
assert_eq!((r.h, r.w, r.frames.len()), (96, 96, 8));
assert_eq!(r.work_pixel_ops, 8 * 96 * 96 * 3);
}
/// A receipt sealed over one clip must not verify against another.
#[test]
fn a_receipt_does_not_vouch_for_a_different_clip() {
let (r, _, _) = seal("int_video_bitstream.json", 10);
let other = raw("video_real_bitstream.json");
let other_bs: serde_json::Value = serde_json::from_slice(&other).unwrap();
assert!(!r.verify_reconstruction(&other, &other_bs));
}
/// Tampering with any checkable field must break the receipt.
#[test]
fn every_checkable_field_is_bound() {
let (base, bytes, bs) = seal("int_video_bitstream.json", 4_200);
// A flipped frame hash breaks the Merkle root.
let mut t = base.clone();
t.frames[2].hash[0] ^= 1;
assert!(!t.verify(), "flipped frame hash");
// Reordering frames breaks the index binding — inter-frame decode is
// order-dependent, so a permuted clip is a different clip.
let mut t = base.clone();
t.frames.swap(1, 3);
assert!(!t.verify(), "permuted frames");
// Inflating the work figure (the denominator of any efficiency claim)
// breaks recomputation.
let mut t = base.clone();
t.work_pixel_ops *= 10;
assert!(!t.verify(), "inflated work");
// Restating the geometry breaks the clip commitment.
let mut t = base.clone();
t.w += 1;
assert!(!t.verify(), "restated geometry");
// A different identity no longer describes this codestream.
let mut t = base.clone();
t.codestream_hash[0] ^= 1;
assert!(!t.verify_reconstruction(&bytes, &bs), "wrong codestream hash");
// And the energy is inside the signature even though it is not
// independently checkable — an intermediary cannot restate it.
let mut t = base.clone();
t.joules_micro = 1;
assert!(!t.verify(), "restated energy");
}
/// Receipts chain like every other class, and the chain link is covered by the
/// signature.
#[test]
fn receipts_chain_by_parent_hash() {
let (first, _, _) = seal("int_video_bitstream.json", 4_200);
let bytes = raw("video_real_bitstream.json");
let bs: serde_json::Value = serde_json::from_slice(&bytes).unwrap();
let second = VideoReceipt::seal_decode(
&key(7),
"did:example:meter",
&bytes,
&bs,
91_000,
Some(chip()),
Some(first.receipt_hash()),
)
.expect("seal");
assert!(second.verify());
assert_eq!(second.parent_receipt_hash, Some(first.receipt_hash()));
let mut t = second.clone();
t.parent_receipt_hash = None;
assert!(!t.verify(), "the chain link is signed");
}
/// A number and its acquisition class stand or fall together — the doctrine
/// this class exists to enforce, checked rather than merely documented.
#[test]
fn an_energy_figure_and_its_class_are_inseparable() {
let (metered, _, _) = seal("int_video_bitstream.json", 4_200);
let (unmetered, _, _) = seal("int_video_bitstream.json", 0);
assert!(metered.verify() && unmetered.verify());
// Stripping the class off a real figure leaves a number nobody can compare.
let mut t = metered.clone();
t.energy_provenance = None;
assert!(!t.verify(), "unlabelled non-zero figure");
// Labelling a measurement that never happened is the more dangerous half:
// it claims a sensor was in the loop when none was.
let mut t = unmetered.clone();
t.energy_provenance = Some(chip());
assert!(!t.verify(), "labelled zero");
// The class is inside the signature, so an intermediary cannot promote a
// modelled figure to a measured one.
let mut t = metered.clone();
t.energy_provenance = Some(Provenance::ModelBased);
assert!(!t.verify(), "restated class");
}
fn hex(b: &[u8]) -> String {
b.iter().map(|x| format!("{x:02x}")).collect()
}
/// A receipt sealed under the three-rung ladder keeps its signed bytes and its
/// JSON rendering. The digests were captured from the legacy encoding (tag
/// byte, no trailing evidence) and pin it: a verifier holding such a receipt
/// must reach the same verdict after the acquisition-class split as before.
#[test]
#[allow(deprecated)] // sealing a legacy HwShunt receipt is the point
fn legacy_labels_keep_their_signed_bytes() {
let (hw, _, _) = seal_as("int_video_bitstream.json", 4_200, Some(Provenance::HwShunt));
let (none, _, _) = seal("int_video_bitstream.json", 0);
assert!(hw.verify() && none.verify());
assert_eq!(
[
hex(&hw.receipt_hash()),
hex(blake3::hash(hw.to_json().as_bytes()).as_bytes()),
hex(&none.receipt_hash()),
],
[
"0dc851f603666496b1358ab427d8a84163c1841eade8970d537bcdc0567b1745",
"1cdcf1ebd778c39aca8614c4aa4d470dc9c5ad7ff680eaf3e1ee7302c39db15b",
"03a88242e999887d0ad9e515d9980755e6aad00989bed8e0ccba35b4bb2dd710",
]
);
}
/// The refined hardware class carries its declared uncertainty into the
/// signature and into the rendered receipt; the same class with no uncertainty
/// does not verify.
#[test]
fn a_refined_class_carries_its_uncertainty_and_cannot_omit_it() {
let (r, _, _) = seal("int_video_bitstream.json", 4_200);
assert!(r.verify());
let j = r.to_json();
assert!(j.contains("\"energy_provenance\":\"OnChipCounter\""), "{j}");
assert!(j.contains("\"energy_uncertainty\":{\"relative_ppm\":30000,\"window_us\":2800000}"), "{j}");
assert!(j.contains("\"energy_counter_filtering\":\"Unknown\""), "{j}");
serde_json::from_str::<serde_json::Value>(&j).expect("the receipt renders as valid JSON");
// Sealed without an uncertainty (by hand, bypassing the checked
// constructor): the signature is valid, the receipt is not.
let undeclared = Provenance::OnChipCounter {
uncertainty: Uncertainty { relative_ppm: 0, window_us: 2_800_000 },
filtering: CounterFiltering::Unknown,
};
let (bad, _, _) = seal_as("int_video_bitstream.json", 4_200, Some(undeclared));
assert!(!bad.verify(), "a hardware class with no declared uncertainty must not verify");
// And a declared uncertainty cannot be tightened after sealing.
let mut t = r.clone();
t.energy_provenance = Some(
Provenance::on_chip_counter(Uncertainty::new(1_000, 2_800_000).unwrap(), CounterFiltering::Unknown)
.unwrap(),
);
assert!(!t.verify(), "restated uncertainty");
}
/// The refined classes' signed bytes, pinned as they were when the hardware
/// class was split. `legacy_labels_keep_their_signed_bytes` holds the legacy
/// encodings; this holds the refined ones, so a byte that leaks into the
/// evidence encoding (`write_signed`) fails here. The digests were captured
/// from the code as the refined classes were introduced and must never be
/// edited to make a test pass.
#[test]
fn refined_labels_keep_their_signed_bytes() {
let (chip_r, _, _) = seal("int_video_bitstream.json", 4_200);
let cal = Provenance::calibrated_instrument(
Uncertainty::new(5_000, 60_000_000).unwrap(),
"https://calibration.example.org/certificates/0001",
)
.unwrap();
let (cal_r, _, _) = seal_as("int_video_bitstream.json", 4_200, Some(cal));
assert!(chip_r.verify() && cal_r.verify());
assert_eq!(
[
hex(&chip_r.receipt_hash()),
hex(blake3::hash(chip_r.to_json().as_bytes()).as_bytes()),
hex(&cal_r.receipt_hash()),
hex(blake3::hash(cal_r.to_json().as_bytes()).as_bytes()),
],
[
"23b6f548184a543fa324066427648152de6bb367f64aaddb9ff608d8af41543d",
"7ece767eb1428faff0d4dd035d1d85e285461bc4610c5af30223a5c0fc20dcc3",
"c6aad993760ff0b23c57a49e64a4a24c568db2af1c3f18b3c11e659c4ffb4151",
"2d5529def21fdbf30524a53c1638f06c6311bd3d0d50e125ba4d3a4b2fcf69bb",
]
);
}
/// A receipt sealed over the `WIV1` payload (`extensions/integer-payloads.md` §3):
/// its identity is BLAKE3 over the payload, it re-derives from the payload alone,
/// and every reconstruction field — frames, clip commitment, geometry, work — is the
/// one the JSON form's receipt carries, since both decode to the same frames.
#[test]
fn a_wiv1_receipt_identifies_the_payload_and_reconstructs_the_same_clip() {
for (bin, json) in [("int_video_bitstream.wiv1", "int_video_bitstream.json"), ("video_real_bitstream.wiv1", "video_real_bitstream.json")] {
let payload = raw(bin);
let r = VideoReceipt::seal_decode_wiv1(&key(7), "did:example:meter", &payload, 4_200, Some(chip()), None).expect("seal");
assert!(r.verify(), "{bin}");
assert!(r.verify_reconstruction_wiv1(&payload), "{bin}: re-decode must reproduce every frame");
assert_eq!(r.codestream_hash, *blake3::hash(&payload).as_bytes(), "{bin}: the identity is the payload's");
let (legacy, json_bytes, _) = seal(json, 4_200);
assert_eq!((&r.frames, r.clip_hash, r.h, r.w, r.work_pixel_ops), (&legacy.frames, legacy.clip_hash, legacy.h, legacy.w, legacy.work_pixel_ops),
"{bin}: the same reconstruction as the JSON form's receipt");
assert_ne!(r.codestream_hash, legacy.codestream_hash);
// Neither receipt vouches for the other's codestream.
assert!(!r.verify_reconstruction_wiv1(&json_bytes), "{bin}: a JSON form is not a WIV1 payload");
assert!(!legacy.verify_reconstruction_wiv1(&payload), "{bin}: the legacy receipt names the JSON bytes");
let mut other = payload.clone();
let at = other.len() - 5;
other[at] ^= 1;
assert!(!r.verify_reconstruction_wiv1(&other), "{bin}: one changed byte");
}
}
/// The signed bytes of receipts sealed over the `WIV1` payload, captured from the
/// code as this identity was introduced: a metered one with the on-chip class, an
/// unmetered one, and one chained to the first. Never edited to make a test pass.
#[test]
fn wiv1_receipts_keep_their_signed_bytes() {
let payload = raw("int_video_bitstream.wiv1");
let metered = VideoReceipt::seal_decode_wiv1(&key(7), "did:example:meter", &payload, 4_200, Some(chip()), None).unwrap();
let unmetered = VideoReceipt::seal_decode_wiv1(&key(7), "did:example:meter", &payload, 0, None, None).unwrap();
let chained = VideoReceipt::seal_decode_wiv1(&key(7), "did:example:meter", &payload, 0, None, Some(metered.receipt_hash())).unwrap();
assert!(metered.verify() && unmetered.verify() && chained.verify());
let got = [
hex(&metered.codestream_hash),
hex(&metered.receipt_hash()),
hex(blake3::hash(metered.to_json().as_bytes()).as_bytes()),
hex(&unmetered.receipt_hash()),
hex(&chained.receipt_hash()),
];
assert_eq!(
got,
[
"277865b574029f700f4fac023de3ab06ae598ee6f8ed726444e91442a6bd59e9",
"52c0ca1c9b383b9ad83226d423b36ecafbef92bf431432c7426a484c0406a742",
"97a7cb3b2598f609d205159e2ef1b2d7fb2d35e429ee161a6a8fbbd8ffdcae52",
"f19f86c9106981096bdbb5ea06926e3543112c26a5f737732938feb51c2b6119",
"58ca49ab785116aec8d2f3b990722e962967cbca6b4d6fe41087343872bd1628",
]
);
}
/// `video_receipt::decode_wiv1` reports a refusal by its code
/// (`extensions/integer-payloads.md` §8), the decode's as well as the parse's: the
/// refusal fixtures of a run-out stream and an unread word, and a JSON form.
#[test]
fn decode_wiv1_reports_refusal_codes() {
let fixture = |name: &str| std::fs::read(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../int-payload-conformance/refusals").join(name)).unwrap();
let code = |p: &[u8]| wai::video_receipt::decode_wiv1(p).map(|_| ()).unwrap_err();
assert_eq!(code(&fixture("wiv1_exhausted.bin")), "stream_exhausted");
assert_eq!(code(&fixture("wiv1_unread_word.bin")), "stream_noncanonical");
assert_eq!(code(&raw("int_video_bitstream.json")), "bad_magic");
}