open-standards/wai/live-conformance/audio_mark_verify.py
Transaction Science 63e856b226
Some checks failed
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 8m12s
WAI operation catalogue / does this change touch it (push) Successful in 8m3s
wai-app and Create / wai-app · does this change touch it (push) Successful in 8m7s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 8m21s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 8m24s
wai-audit collector and player integration / does this change touch it (push) Successful in 8m6s
wai-key-proxy / does this change touch it (push) Successful in 7m59s
wai-fleet service / does this change touch it (push) Successful in 8m2s
wai-quantum studio and desktop / does this change touch it (push) Successful in 1m40s
wai-ledger service / does this change touch it (push) Successful in 1m42s
wai-quantum for JavaScript / does this change touch it (push) Successful in 1m43s
wai-sink-android native sink library / does this change touch it (push) Successful in 1m41s
WAI Studio / does this change touch it (push) Successful in 1m40s
wai-sink-swift native sink package / does this change touch it (push) Successful in 1m41s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 46s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 1m40s
wai-fleet service / service · macos (push) Successful in 47s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 5m44s
wai-ledger service / service · macos (push) Successful in 50s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 4m37s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Has been cancelled
wai-fleet service / service · linux (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Has been cancelled
wai-ledger service / service · linux (push) Has been cancelled
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Has been cancelled
WAI Studio / Studio in WebKit · linux (push) Has been cancelled
WAI Studio / Studio in Chromium and Firefox · macos (push) Has been cancelled
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 7m9s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 10m50s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 10m5s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 8s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 8s
wai-audit collector and player integration / collector · linux (push) Successful in 1m50s
wai-key-proxy / proxy · linux (push) Successful in 1m37s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 3m28s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 9m6s
wai-quantum studio and desktop / studio · browser (push) Successful in 7m10s
wai-quantum for JavaScript / javascript · linux (push) Successful in 6m42s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 9m10s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 2m38s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 2m38s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 5m0s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 7m33s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 17m45s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 1m42s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 4m49s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 4m25s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 7m38s
wai: register wai-mark:band64, a watermark for sound, peer of tent64
synthesis §7.10 registers the second marking layer for speech and other audio: the same
8-byte payload and BCH code as tent64, the same marking and detection records and failure
codes (audio states rate, channels and length), embedded by a pinned integer derivation in
the band energies of the mono mix and read key-free after trims, rate and level changes and
the codecs §7.10.7 measures. robustness-evidence registers audio corpora, ten pinned
transforms of sound and the lossy codecs as measured transforms, whose records are stated.

Reference in wai-rs (synthesis::mark::audio, audio_mark, robustness::audio,
wai_audio_mark_vectors), second implementation in _wai_audio_mark.py with
audio_mark_verify.py, corpus in live-conformance/audio-mark/ with records measured on
generated voices and music and on recorded speech named by digest.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-08 16:20:24 -05:00

428 lines
19 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""Second implementation of the audio scheme of the second marking layer, `wai-mark:band64`
(extensions/synthesis.md §7.10, §13), over the corpus `live-conformance/audio-mark/`.
Written from the extensions' text. It shares no code with wai-rs: the scheme (the cosine tables,
the frames, the integer logarithm, the stream, the shuffle, the signs, the mask, the embedding
with its three syntheses, the detector with its offsets and phases) and the pinned transforms of
sound are _wai_audio_mark.py's, written from synthesis §7.10 and robustness-evidence §4.1, the
code _wai_mark.py's, written from §7.5.3; every case is verified by synthesis_verify.py with §7.6's
checks; every robustness record by robustness_verify.py, which reruns the conformance record's
harness end to end. It reads from the extension the scheme's definition and digest (§7.10.1),
the shuffle's first entries (§7.10.3), the false-positive bound (§7.10.6), and the tables and the
claims of §7.10.7.
python3 -I audio_mark_verify.py <live-conformance/audio-mark>
It checks that every audio file is named by its SHA-256; that the definition is §7.10.1's and
has its digest, and the cosine tables the digest the definition pins; that the layout is
§7.10.3's; that every embedding, detection and battery sample of the corpus is what this
implementation gives; that every case gets the outcome, the reason, the place and the statements
it states; that the robustness records verify, the conformance record reproduced; and that
§7.10.7's tables are the measurement's and its claims attacks the records show survived. Then it
mutates copies of the corpus and requires each to fail, and weakens its own verifier in turn and
requires the corpus to catch each. Exit status 0 only if all of that holds. Python 3.8 or later;
standard library only.
"""
import copy
import hashlib
import json
import math
import os
import re
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import _wai_audio_mark as A # noqa: E402
import _wai_mark as TENT # noqa: E402
import synthesis_verify as SV # noqa: E402
import robustness_verify as RV # noqa: E402
def sha(b):
return hashlib.sha256(b).digest()
def sec(head):
return SV.section(SV._TEXT, head)
def fold(s):
return " ".join(s.split())
# ---------------------------------------------------------------- what the extension states
def text_definition():
block = sec("#### 7.10.1 ").split("```")[1]
return "".join(line.strip() for line in block.strip().splitlines()).encode("utf-8")
def text_shuffle_head():
m = re.search(r"π begins ([0-9, ]+), and the corpus", fold(sec("#### 7.10.3 ")))
return [int(x) for x in m.group(1).split(",")] if m else None
def text_fp():
m = re.search(r"2\^−([0-9.]+), about", fold(sec("#### 7.10.6 ")))
return "-" + m.group(1) if m else None
def text_tables():
"""§7.10.7: each table's rows, as {attack: {column: cell}}, by the table's first header."""
out = {}
s = sec("#### 7.10.7 ")
head = None
for line in s.splitlines():
if line.startswith("| attack"):
head = [c.strip().strip("`") for c in line.strip("|").split("|")]
out[head[1]] = {}
elif head and line.startswith("| `"):
cells = [c.strip() for c in line.strip("|").split("|")]
out[head[1]][cells[0].strip("`")] = dict(zip(head[1:], cells[1:]))
elif not line.startswith("|"):
head = None
return out
def text_claims():
"""§7.10.7: the attacks it claims to survive."""
m = re.search(r"\*\*claims to survive\*\* ([^.]*)\.", fold(sec("#### 7.10.7 ")))
return re.findall(r"`([a-z0-9/.+-]+)`", m.group(1)) if m else None
def fp_log2(attempts):
n, term, v = 248, 1.0, 0.0
for i in range(30):
v += term
term = term * (n - i) / (i + 1)
return "%.2f" % (math.log2(attempts) + 58 + math.log2(v) - n)
# ---------------------------------------------------------------- the corpus's audio
_MARKED = {}
def marked(rate, channels, buf, payload):
k = (sha(buf), rate, channels, payload)
if k not in _MARKED:
_MARKED[k] = A.embed_bytes(rate, channels, buf, payload)
return _MARKED[k]
_READ = {}
def detect(rate, channels, buf):
k = (sha(buf), rate, channels)
if k not in _READ:
_READ[k] = A.detect(rate, channels, buf)
return _READ[k]
def detected_json(d):
if d is None:
return None
return {"payload": d[0].hex(), "offset": d[1], "phase": d[2], "errors": d[3]}
def derive(src, stored):
"""A source of §13: stored audio, marked under a payload, then a pinned transform, then one
sample's lowest bit flipped. (rate, channels, buffer)."""
buf = stored[src["audio"]]
rate, ch = src["rate"], src["channels"]
if src["marked"] is not None:
buf = marked(rate, ch, buf, bytes.fromhex(src["marked"]))[0]
if src["derive"] is not None:
d = src["derive"]
name = d["transform"].split(":", 1)[1]
rate, chans = A.attack(name, d["params"], rate, A.unpack(buf, ch), d["seed"])
ch = len(chans)
buf = A.pack(chans)
if src["flip"] is not None:
b = bytearray(buf)
b[2 * src["flip"]] ^= 1
buf = bytes(b)
return rate, ch, buf
def bits(b):
return "".join("1" if x else "0" for x in b)
def check(doc, battery, scheme_bytes, stored, files, classes, only=None):
fails = []
want = lambda part: only is None or part in only # noqa: E731
for h, b in stored.items():
if sha(b).hex() != h:
fails.append("audio %s is not named by its SHA-256" % h)
sc = doc["scheme"]
if scheme_bytes != text_definition() or sha(scheme_bytes) != SV.SCHEME_DIGEST_A or sc["digest"] != SV.SCHEME_DIGEST_A.hex():
fails.append("the definition is not §7.10.1's, or its digest is not the one §7.10.1 states")
try:
definition = json.loads(scheme_bytes)
except ValueError:
definition = {}
tables = sha(A.tables_bytes()).hex()
if definition.get("cosine") != [A.ONE, tables] or sc["tables"] != tables:
fails.append("the cosine tables do not have the digest the definition pins")
if definition.get("step") != A.STEP or definition.get("gate") != A.GATE or definition.get("bands") != list(A.BANDS):
fails.append("the definition's parameters are not this implementation's")
head = text_shuffle_head()
if head is None or A.PERM[:len(head)] != head or sc["shuffle_first"] != A.PERM[:16] or sc["shuffle_last"] != A.PERM[-16:]:
fails.append("the shuffle is not §7.10.3's")
if sc["signs_first"] != A.SIGN[:16] or sc["mask"] != bits(A.MASK):
fails.append("the signs or the mask are not §7.10.3's")
if TENT.decode(A.MASK) is not None:
fails.append("the mask decodes to a payload")
fp = fp_log2(A.PERIOD * A.PHASES)
if sc["false_positive_log2"] != fp or text_fp() != fp:
fails.append("the false-positive bound is not %s (§7.10.6)" % fp)
for e, l in doc["lg"]:
if A.lg(int(e)) != l:
fails.append("lg(%s) is not %d" % (e, l))
for a, s in doc["shift"]:
if A.shift(a) != s:
fails.append("S(%d) is not %d" % (a, s))
for e in (doc["embeds"] if want("embeds") else []):
try:
buf = stored[e["audio"]]
out, gains = marked(e["rate"], e["channels"], buf, bytes.fromhex(e["payload"]))
g = b"".join((x & 0xFFFF).to_bytes(2, "big") for x in gains).hex()
if sha(out).hex() != e["marked"] or g != e["gains"] or len(gains) != e["cells"]:
fails.append("embed %s: the marked samples or the gains differ" % e["name"])
except Exception as x: # noqa: BLE001
fails.append("embed %s: %r" % (e["name"], x))
for d in (doc["detects"] if want("detects") else []):
try:
rate, ch, buf = derive(d["source"], stored)
got = detected_json(detect(rate, ch, buf))
if (sha(buf).hex(), rate, ch, len(buf) // (2 * ch), got) != (d["samples"], d["rate"], d["channels"], d["length"], d["detected"]):
fails.append("detect %s: %s" % (d["name"], got))
except Exception as x: # noqa: BLE001
fails.append("detect %s: %r" % (d["name"], x))
voice = next(e for e in doc["embeds"] if e["name"] == "voice")
vbuf = stored[voice["audio"]]
for x in (doc["battery_sample"] if want("battery") else []):
try:
buf = marked(voice["rate"], voice["channels"], vbuf, bytes.fromhex(voice["payload"]))[0] if x["which"] == "marked" else vbuf
name, params = x["transform"].split(":", 1)[1], x["params"]
rate, chans = A.attack(name, params, voice["rate"], A.unpack(buf, voice["channels"]), x["seed"])
y = A.pack(chans)
got = detected_json(detect(rate, len(chans), y))
if (sha(y).hex(), rate, len(chans), got) != (x["samples"], x["rate"], x["channels"], x["detected"]):
fails.append("battery sample %s of the %s voice: %s" % (x["attack"], x["which"], got))
except Exception as e: # noqa: BLE001
fails.append("battery sample %s: %r" % (x.get("attack"), e))
for v in (doc["cases"] if want("cases") else []):
case = dict(v, room=None)
try:
case["decoded"] = [{"object": d["object"], "samples": derive(d["source"], stored)[2].hex()} for d in v["decoded"]]
case["unmarked"] = [{"object": d["object"], "samples": derive(d["source"], stored)[2].hex()} for d in v["unmarked"]]
case["priors"] = []
got = SV.outcome(case, classes)
except Exception as e: # noqa: BLE001
got = {"outcome": "unreadable: %r" % (e,)}
if got != SV.stated(v):
fails.append("case %s: %s" % (v["name"], json.dumps(got)[:300]))
if want("measurement"):
fails += check_measurement(battery, files)
if want("records"):
fails += check_records(files, stored)
return fails
def check_measurement(battery, files):
"""§7.10.7: its tables are the measurement's, and its claims attacks every record shows
survived."""
fails = []
t = text_tables()
rows = {}
for r in battery["table"]:
rows.setdefault(r["attack"], {})[r["set"]] = r
measured = {}
for k in sorted(files):
if k.startswith("robustness/measured/measurement-"):
m = json.loads(files[k])
for r in m["table"]:
measured.setdefault(r["attack"], {})[r["set"]] = r
pinned = t.get("voice", {})
if not pinned:
fails.append("§7.10.7 has no table of the pinned attacks")
for attack, cells in pinned.items():
for col, cell in cells.items():
src = rows if col in ("voice", "music") else measured
r = src.get(attack, {}).get(col)
want = "%d / %d" % (r["survived"], r["items"]) if r else None
if r and r["survived"]:
want += " (%d)" % r["errors_max"]
if want is None or cell != want:
fails.append("§7.10.7 %s, %s: %s, the measurement %s" % (attack, col, cell, want))
codecs = t.get("speech", {})
for attack, cells in codecs.items():
for col, cell in cells.items():
r = measured.get(attack, {}).get(col)
want = "%d / %d" % (r["survived"], r["items"]) if r else None
if r and r["survived"]:
want += " (%d)" % r["errors_max"]
if want is None or cell != want:
fails.append("§7.10.7 %s, %s: %s, the measurement %s" % (attack, col, cell, want))
claims = text_claims()
if claims is None:
fails.append("§7.10.7 states no claim")
else:
everything = dict(rows)
for a, c in measured.items():
everything.setdefault(a, {}).update(c)
for a in claims:
sets = everything.get(a, {})
if not sets or any(r["survived"] != r["items"] or r["false_positives"] for r in sets.values()):
fails.append("§7.10.7 claims %s, which a set did not survive" % a)
if battery["false_positive_log2"] != fp_log2(A.PERIOD * A.PHASES):
fails.append("the measurement's bound is not §7.10.6's")
return fails
def check_records(files, stored):
"""robustness-evidence §10: the scheme's records, each case verified by robustness_verify."""
fails = []
samples = {h: b for h, b in stored.items()}
get = lambda k: files[k].decode("utf-8") if k in files else None # noqa: E731
def run(label, records, want):
corpora = {i: c for i, (_, c) in enumerate(records) if c is not None}
case = {"records": [r for r, _ in records], "corpora": corpora, "samples": samples, "implements": [A.SCHEME],
"require_reproduced": False}
got = RV.verify_case(case)
if got[0] != "accept":
return ["%s: refused %s at %d" % (label, got[1], got[2])]
st = [s["status"] for s in got[1]]
return [] if st == want else ["%s: %s, not %s" % (label, st, want)]
cr, cd = get("robustness/records/band64-conformance.json"), get("robustness/corpus/band64-conformance.json")
if cr is None or cd is None:
return ["the conformance record or its corpus is missing"]
fails += run("the conformance record", [(cr, cd)], ["reproduced"])
gen = [(get("robustness/records/band64-%s.json" % s), get("robustness/corpus/band64-%s.json" % s)) for s in ("voice", "music")]
claim = get("robustness/records/band64-claim.json")
if any(r is None or c is None for r, c in gen) or claim is None:
fails.append("a generated set's record, its corpus or the claim is missing")
else:
fails += run("the generated sets' records and claim", gen + [(claim, None)], ["stated"] * 3)
meas = []
for k in sorted(files):
f = k[len("robustness/measured/"):]
if not k.startswith("robustness/measured/") or not f.endswith(".json") or f.startswith(("measurement-", "corpus-")) or f == "claim.json" or f.startswith("negatives"):
continue
name = f[:-len(".json")]
c = get("robustness/corpus/band64-%s.json" % name) or get("robustness/measured/corpus-%s.json" % name)
if c is None:
fails.append("%s: no corpus document" % k)
meas.append((get(k), c))
if meas:
mc = get("robustness/measured/claim.json")
fails += run("the measured records and their claim", meas + [(mc, None)], ["stated"] * (len(meas) + 1))
return fails
# ---------------------------------------------------------------- mutations and weakenings
def mutations(doc, battery, scheme_bytes, stored, files):
out = []
def mutate(label, f):
d, b, s, st, fs = copy.deepcopy(doc), copy.deepcopy(battery), scheme_bytes, dict(stored), dict(files)
r = f(d, b, st, fs)
if isinstance(r, bytes):
s = r
out.append((label, d, b, s, st, fs))
mutate("a byte of the definition", lambda d, b, st, fs: scheme_bytes.replace(b'"step":848', b'"step":849'))
mutate("the music's marked digest", lambda d, b, st, fs: d["embeds"][1].update(marked=SV.flip_hex_digit(d["embeds"][1]["marked"], 5)))
mutate("a detection that reads the unmarked voice as marked",
lambda d, b, st, fs: d["detects"][1].update(detected={"payload": d["embeds"][0]["payload"], "offset": 0, "phase": 0, "errors": 0}))
mutate("a trimmed detection's offset", lambda d, b, st, fs: [x.update(detected=dict(x["detected"], offset=x["detected"]["offset"] + 1))
for x in d["detects"] if x["detected"] and x["detected"]["offset"]][:1])
mutate("a battery sample's result digest", lambda d, b, st, fs: d["battery_sample"][3].update(samples=SV.flip_hex_digit(d["battery_sample"][3]["samples"], 1)))
mutate("a case's statement", lambda d, b, st, fs: d["cases"][0]["statements"]["markings"][0].update(status="stated"))
mutate("a tally of the measurement", lambda d, b, st, fs: b["table"][0].update(survived=b["table"][0]["survived"] - 1))
mutate("a claim of an attack a set lost", lambda d, b, st, fs: [r.update(survived=0) for r in b["table"] if r["attack"] == "mulaw"][:1])
return out
def weakened():
"""The verifier with one of §7.6's checks or §7.3's inheritance dropped, and the scheme with
one of its own steps dropped: each with the parts of the corpus it is run on."""
return [
("the marking not recomputed", SV, "recomputes", lambda *a: True, None),
("the detection not run again", SV, "reproduces", lambda *a: True, None),
("no agreement by inheritance", SV, "inherits", lambda c, p, by_link: False, None),
("one phase only", A, "PHASES", 1, {"detects"}),
("no gate", A, "GATE", -(1 << 40), {"embeds"}),
]
def main(corpus_dir):
fails = []
with open(os.path.join(HERE, "..", "registry", "capabilities.json"), encoding="utf-8") as f:
classes = {c["capability"]: c["replicate"] for c in json.load(f)["capabilities"]}
files = RV.load(corpus_dir)
doc = json.loads(files["vectors.json"])
battery = json.loads(files["battery-band64.json"])
scheme_bytes = files["scheme-band64.json"]
stored = {k[len("audio/"):-len(".pcm")]: v for k, v in files.items() if k.startswith("audio/")}
base = check(doc, battery, scheme_bytes, stored, files, classes)
for b in base:
print("FAIL " + b)
print(("PASS" if not base else "FAIL") + " the scheme, %d embeddings, %d detections, %d battery samples, %d cases and the records"
% (len(doc["embeds"]), len(doc["detects"]), len(doc["battery_sample"]), len(doc["cases"])))
fails += base
seen = {v.get("reason") for v in doc["cases"]}
missing = [r for r in SV.MARK_ONLY if r not in seen]
print(("PASS" if not missing else "FAIL") + " every code only a scheme's corpus gives (§13) refuses a case: " + ", ".join(SV.MARK_ONLY))
fails += ["codes no case gives: %s" % missing] if missing else []
for label, d, b, s, st, fs in mutations(doc, battery, scheme_bytes, stored, files):
caught = check(d, b, s, st, fs, classes)
print(("PASS" if caught else "FAIL") + " mutated copy fails: %s%s" % (label, " (%s)" % caught[0][:100] if caught else ""))
if not caught:
fails.append("a mutated copy verifies: %s" % label)
for label, mod, name, value, only in weakened():
saved = getattr(mod, name)
setattr(mod, name, value)
# The memos of embeddings, detections and harness runs are of the scheme's functions:
# only a weakening of the scheme itself makes them stale.
if mod is A:
_READ.clear()
_MARKED.clear()
SV._EMBEDDED.clear()
SV._DETECTED.clear()
RV.HARNESS_MEMO.clear()
try:
caught = check(doc, battery, scheme_bytes, stored, files, classes, only)
finally:
setattr(mod, name, saved)
if mod is A:
_READ.clear()
_MARKED.clear()
SV._EMBEDDED.clear()
SV._DETECTED.clear()
RV.HARNESS_MEMO.clear()
print(("PASS" if caught else "FAIL") + " the corpus catches a verifier with %s%s" % (label, " (%s)" % caught[0][:100] if caught else ""))
if not caught:
fails.append("a weakened verifier passes: %s" % label)
for f in fails:
print("FAIL " + f)
print(("PASS" if not fails else "FAIL") + " audio-mark corpus")
return 1 if fails else 0
if __name__ == "__main__":
if len(sys.argv) != 2:
print("usage: audio_mark_verify.py <live-conformance/audio-mark>", file=sys.stderr)
sys.exit(2)
sys.exit(main(sys.argv[1]))