open-standards/wai/claim-conformance/_blake3.py
Transaction Science ce9207ac3c wai: the staged-delivery corpus and its independent verifier
staged-conformance/ holds stage sets and the steps a sink takes with them:
image layers over a pinned integer image base (identity, up2 to even and odd
sizes) and over a PNG base; video layers per frame and per GOP, with prev
runs, over integer motion bases and over a pinned neural-keyframe clip; audio
layers over a pinned integer audio base, and a stereo rate ladder over a FLAC
base; a splat attribute layer; and one case per refusal and order rule
(another base, a wrong producer, a missing layer, conflicts held and after an
application, out of order, a fallback base, geometry, truncation, a malformed
table, q of 0, a word after the last symbol, a stream that runs out, clamped
and bypassed residuals, malformed refines, a capability that is not a
refinement, a base not admitted, inclusion-only evidence, a cost limit, a
missed deadline, the hold bound). Each case's case.json states what a sink
reports at every step and holds at the end; schedule.json holds arrival
traces and what a sink presents.

wai_staged_vectors gen writes the corpus; verify regenerates it byte for
byte, replays every case through StageSink, decodes the integer bases with
their pins against stage0.bin and checks their tiers. staged_verify.py is a
standard-library reimplementation of the envelope, refines, WIR1, the sink's
algorithm, tiers and stage hashes, and the PNG, FLAC and WIV1 keyframe-0
decodes; it checks every layer application in every case.

The pure-Python BLAKE3 moves from claim_verify.py to _blake3.py, which both
verifiers import. A unit held and decided within one step is reported by its
decision alone.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-02 00:27:50 -04:00

75 lines
2.7 KiB
Python

"""BLAKE3 in hash mode, written from its specification in pure Python.
Shared by the claim-conformance verifier (`claim_verify.py`) and the staged-delivery
verifier (`../staged-conformance/staged_verify.py`), which import `blake3` from here. It
shares no code with wai-rs, which computes the same hashes with the `blake3` crate.
"""
_IV = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19]
_PERM = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8]
_CHUNK_START, _CHUNK_END, _PARENT, _ROOT = 1, 2, 4, 8
_M32 = 0xFFFFFFFF
def _rotr(x, n):
return ((x >> n) | (x << (32 - n))) & _M32
def _g(s, a, b, c, d, x, y):
s[a] = (s[a] + s[b] + x) & _M32
s[d] = _rotr(s[d] ^ s[a], 16)
s[c] = (s[c] + s[d]) & _M32
s[b] = _rotr(s[b] ^ s[c], 12)
s[a] = (s[a] + s[b] + y) & _M32
s[d] = _rotr(s[d] ^ s[a], 8)
s[c] = (s[c] + s[d]) & _M32
s[b] = _rotr(s[b] ^ s[c], 7)
def _compress(cv, m, counter, blen, flags):
s = list(cv) + _IV[:4] + [counter & _M32, (counter >> 32) & _M32, blen, flags]
m = list(m)
for r in range(7):
_g(s, 0, 4, 8, 12, m[0], m[1]); _g(s, 1, 5, 9, 13, m[2], m[3])
_g(s, 2, 6, 10, 14, m[4], m[5]); _g(s, 3, 7, 11, 15, m[6], m[7])
_g(s, 0, 5, 10, 15, m[8], m[9]); _g(s, 1, 6, 11, 12, m[10], m[11])
_g(s, 2, 7, 8, 13, m[12], m[13]); _g(s, 3, 4, 9, 14, m[14], m[15])
if r < 6:
m = [m[i] for i in _PERM]
return [s[i] ^ s[i + 8] for i in range(8)] + [s[i + 8] ^ cv[i] for i in range(8)]
def _words(block):
block = block + b"\0" * (64 - len(block))
return [int.from_bytes(block[i:i + 4], "little") for i in range(0, 64, 4)]
def _chunk_output(chunk, counter):
blocks = [chunk[i:i + 64] for i in range(0, len(chunk), 64)] or [b""]
cv = _IV
for j, b in enumerate(blocks[:-1]):
cv = _compress(cv, _words(b), counter, 64, _CHUNK_START if j == 0 else 0)[:8]
last = blocks[-1]
return (cv, _words(last), counter, len(last), _CHUNK_END | (_CHUNK_START if len(blocks) == 1 else 0))
def _cv(out):
cv, w, c, bl, f = out
return _compress(cv, w, c, bl, f)[:8]
def blake3(data: bytes) -> bytes:
chunks = [data[i:i + 1024] for i in range(0, len(data), 1024)] or [b""]
stack = []
for idx, ch in enumerate(chunks[:-1]):
cv = _cv(_chunk_output(ch, idx))
total = idx + 1
while total & 1 == 0:
cv = _cv((_IV, stack.pop() + cv, 0, 64, _PARENT))
total >>= 1
stack.append(cv)
out = _chunk_output(chunks[-1], len(chunks) - 1)
while stack:
out = (_IV, stack.pop() + _cv(out), 0, 64, _PARENT)
cv, w, _, bl, f = out
return b"".join(x.to_bytes(4, "little") for x in _compress(cv, w, 0, bl, f | _ROOT)[:8])