open-standards/wai/live-conformance/sink_energy_verify.py
Transaction Science 3d79462a09 sink_energy_verify.py: the measured tables are required
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 20:26:51 -04:00

1742 lines
81 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
"""Independent verifier of the sink-energy corpus (extensions/sink-energy.md).
Written from the extension's text and the sections of energy-measurement, jwp-receipts and
live-metering it cites. It shares no code with wai-rs, which generates the corpus, and never
runs it. It checks Ed25519 signatures with ../claim-conformance/_ed25519.py, WAI's strict
rule (SPEC §7 *Signatures*) written from RFC 8032 with the standard library, and reads each
per-hop record `WMH1` with the live-metering corpus's own second implementation,
live_metering_verify.py (live-metering §3.6, §3.5). Everything else is here, from the text:
- RFC 8785 canonical JSON over the values a record may hold, and a JSON reader that keeps
duplicate members and non-integer numbers visible, so that §7 step 1 can refuse them;
- the three records (§3): their shape (§7 step 1), signature (step 2), classes (step 3)
and identities;
- the decode table (§4, step 4): the readings recomputed into rounds (§4.3), each round's
figure and least declaration under energy-measurement §6.2 from rest, the row's status,
median, range, verdict and the declaration floor `max(p, q)` (§4.5);
- the segment receipt (§5, step 5): its method, the bounded bracket (`Wn = Wd = 1`,
`N = 0`), the table formula against the held table, the estimator
`estimator-cpu-time/1` (energy-measurement §9.4), and the chain (§5.3);
- the session receipt (§6, step 6): its hop entries, the display estimator
`estimator-display/1` (energy-measurement §9.5), a hop's figure under the sole-user
rule against its `WMH1` record, the streams against the segment receipts, and the sink-decode part's figure,
class and declaration ⌈Σ(Fᵢ·pᵢ)/ΣFᵢ⌉ (§6.3);
all with Python's integers and no floating point.
For every case of vectors.json it requires the outcome the corpus states, and for an
accepted case its identity; of the corpus, that every reason of §8 refuses a case and that
§8 lists exactly the reasons this verifier raises (and its prose exactly the row and
unmetered reasons it knows); for every measured table under tables/<sink>/, that it is
accepted with its readings held, and that its readings and procedure are the files its
digests name. Then it mutates copies of the corpus, one defect each (re-signing a mutated
record with a key of its own where the defect must reach a rule past the signature), and
requires every copy to fail, most of them with the reason the text gives the defect.
python3 -I sink_energy_verify.py <live-conformance/sink-energy>
python3 -I sink_energy_verify.py --table <dir>
python3 -I sink_energy_verify.py --self-test
`--table <dir>` verifies one measured table directory, <dir>/table.json, readings.json and
procedure.txt, exactly as each tables/<sink>/ of the corpus is verified: the table accepted
(§7 steps 1–4) with its readings held, `readings_sha256` the SHA-256 of readings.json's
bytes and `procedure_sha256` that of procedure.txt's, and its rows summarised. The hardware
jobs of continuous integration run it on a table the procedure has just written (§9).
Exit status 0 only if every check holds and every mutated copy fails (with `--table`, only
if that table 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)
sys.path.insert(0, os.path.join(HERE, "..", "claim-conformance"))
import live_metering_verify as LMV # noqa: E402
import _ed25519 as ED # noqa: E402
TABLE, SEGMENT, SESSION = "table", "segment", "session"
# §3: first member, signing domain, identity domain.
KINDS = {
TABLE: ("wai_sink_table", b"wai:sink-table\x01", b"wai:sink-table-id\x01"),
SEGMENT: ("wai_sink_segment", b"wai:sink-segment\x01", b"wai:sink-segment-id\x01"),
SESSION: ("wai_sink_session", b"wai:sink-session\x01", b"wai:sink-session-id\x01"),
}
MAX = 2 ** 53 - 1
U32 = 2 ** 32 - 1
FLOOR = 288676 # energy-measurement §2.3
LIVE_SPAN_US = 300000 # energy-measurement §3.1, sink-energy §4.5 rule 2
# §4.2 and energy-measurement §9.2, §9.3: the counter profiles and their minimum windows.
MINIMUM_US = {"macos-task": 1000000, "macos-gpu": 1000000, "linux-rapl": 1000000, "linux-nvml": 5000000}
CPU_EST = "estimator-cpu-time/1"
DISPLAY_EST = "estimator-display/1"
PROFILES = frozenset(MINIMUM_US) | {CPU_EST, DISPLAY_EST} # §2 *Profile*
# §4.2, in energy-measurement §9.1's fabrics.
FABRICS = {"macos-task": ["cpu"], "linux-rapl": ["cpu"], CPU_EST: ["cpu"], "macos-gpu": ["gpu"], "linux-nvml": ["gpu"]}
# energy-measurement §2, strongest first.
CLASSES = ("CalibratedInstrument", "OnChipCounter", "HwShunt", "ModelBased", "Estimator")
RANK = {c: i for i, c in enumerate(CLASSES)}
HARDWARE = ("CalibratedInstrument", "OnChipCounter")
FILTERING = ("On", "Off", "Unknown")
COUNTER_STATUS = ("live", "frozen", "needs-privilege", "no-counter", "not-implemented", "implausible")
ABSENT_REASONS = ("no_decoder", "no_work_item", "no_hardware_path", "no_counter")
ROUND_RULES = ("too_few_samples", "rail_not_live", "window_short", "empty_burst", "no_marginal",
"below_attribution_floor", "figure_zero", "not_declarable")
ROW_REASONS = ABSENT_REASONS + ROUND_RULES + ("noisy",) # §8 *row reasons*
UNMETERED_REASONS = ("no_counter", "rail_not_live", "window_short", "no_marginal", "below_attribution_floor",
"figure_zero", "not_declarable", "not_reported") # §8 *unmetered reasons*
ORIGIN, RELAY, SINK_DECODE, DISPLAY = 1, 2, 3, 4 # §6.2's roles
ROLE_NAME = {ORIGIN: "origin", RELAY: "relay", SINK_DECODE: "sink decode", DISPLAY: "display"}
MARKER_REASONS = ("not_reported", "hop_unmetered", "hop_shared", "unmetered", "display_undeclared")
PART_REASONS = {"origin": ("not_reported", "hop_unmetered", "hop_shared"),
"relay": ("not_reported", "hop_unmetered", "hop_shared"),
"sink_decode": ("unmetered",), "display": ("display_undeclared", "unmetered")}
PART_COVERAGE = {"origin": "Partial", "relay": "Partial", "display": "Whole"} # §6.2
ROLE_REASONS = {ORIGIN: PART_REASONS["origin"], RELAY: PART_REASONS["relay"], SINK_DECODE: PART_REASONS["sink_decode"],
DISPLAY: PART_REASONS["display"]}
ROLE_COVERAGE = {ORIGIN: "Partial", RELAY: "Partial", DISPLAY: "Whole"}
FILTER_BYTE = {0: "Unknown", 1: "Off", 2: "On"} # energy-measurement §2.7
# Unicode White_Space, for a calibration reference "not empty once trimmed" (jwp-receipts §2.4.5).
WHITE_SPACE = frozenset([0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x20, 0x85, 0xA0, 0x1680, 0x2028, 0x2029, 0x202F, 0x205F,
0x3000] + list(range(0x2000, 0x200B)))
REASONS = [
"record_malformed", "signature_invalid", "hwshunt_forbidden", "energy_class_invalid", "unmetered_as_zero",
"table_rounds_invalid", "table_row_order", "table_row_status", "table_row_figure", "table_row_declaration",
"table_readings_mismatch", "segment_method_class", "segment_rail_not_live", "segment_window_short",
"segment_below_floor", "segment_figure_mismatch", "segment_declaration_below", "segment_table_mismatch",
"segment_estimator_mismatch", "segment_chain_broken", "split_part_invalid", "split_display_mismatch",
"split_hop_mismatch", "split_decode_mismatch", "session_streams_mismatch",
]
class Refused(Exception):
"""A refusal: the reason of §8, and where and why, for a reader of the output."""
def __init__(self, reason, why=""):
super().__init__(reason)
self.reason, self.why = reason, why
def need(ok, reason, why):
if not ok:
raise Refused(reason, why)
def sha(*parts):
h = hashlib.sha256()
for p in parts:
h.update(p)
return h.digest()
# ---------------------------------------------------------------- JSON: reading and RFC 8785
class JObj(dict):
"""A JSON object in its wire order; `dup` is set when a member name repeats (§7 step 1)."""
dup = False
class JNum:
"""A number no record admits: a fraction, an exponent, a sign or a constant
(jwp-receipts §2.4.3's integers, which §2 adopts)."""
def __init__(self, text):
self.text = text
def __repr__(self):
return "JNum(%s)" % self.text
def __deepcopy__(self, memo):
return self
def _pairs(ps):
o = JObj()
for k, v in ps:
if k in o:
o.dup = True
o[k] = v
return o
def _int(text):
return JNum(text) if text.startswith("-") else int(text)
def loads(text):
return json.loads(text, object_pairs_hook=_pairs, parse_float=JNum, parse_int=_int, parse_constant=JNum)
_ESC = {'"': '\\"', "\\": "\\\\", "\b": "\\b", "\f": "\\f", "\n": "\\n", "\r": "\\r", "\t": "\\t"}
def _jstr(s):
out = ['"']
for ch in s:
o = ord(ch)
if ch in _ESC:
out.append(_ESC[ch])
elif o < 0x20:
out.append("\\u%04x" % o)
elif 0xD800 <= o <= 0xDFFF:
raise ValueError("a lone surrogate is not I-JSON")
else:
out.append(ch)
out.append('"')
return "".join(out)
def jcs(v):
"""RFC 8785 over strings, integers from 0 to 2⁵³ − 1, null, arrays and objects: members
sorted by their UTF-16 code units, no whitespace, integers in plain decimal, strings
escaped as §3.2.2.2 writes them. Anything else raises ValueError."""
out = []
def enc(x):
if x is None:
out.append("null")
elif type(x) is int:
if not 0 <= x <= MAX:
raise ValueError("an integer outside 0 to 2^53 - 1")
out.append(str(x))
elif type(x) is str:
out.append(_jstr(x))
elif type(x) is list:
out.append("[")
for i, y in enumerate(x):
if i:
out.append(",")
enc(y)
out.append("]")
elif isinstance(x, dict):
if getattr(x, "dup", False):
raise ValueError("a duplicate member")
out.append("{")
for i, k in enumerate(sorted(x, key=lambda k: k.encode("utf-16-be"))):
if i:
out.append(",")
out.append(_jstr(k))
out.append(":")
enc(x[k])
out.append("}")
else:
raise ValueError("a value JCS is not used for here: %r" % (x,))
enc(v)
return "".join(out).encode("utf-8")
# ---------------------------------------------------------------- §7 step 1: shape
INT, STR, HEX32, HEX64, DECODER, DATE, FABRIC_LIST = "int", "str", "hex32", "hex64", "decoder", "date", "fabrics"
FABRIC_TERMS = ("cpu", "gpu", "media", "neural") # energy-measurement §9.1
def nul(s):
return ("null", s)
def enum(*v):
return ("enum", frozenset(v))
def const(v):
return ("const", v)
def arr(s):
return ("arr", s)
def pair(s):
return ("pair", s)
def obj(members):
return ("obj", members)
_DEC_BUILTIN = re.compile(r"builtin:[a-z0-9_-]{1,64}@[0-9][A-Za-z0-9.+-]{0,63}")
_DEC_PLATFORM = re.compile(r"platform:[a-z0-9-]{1,64}")
_DATE = re.compile(r"([0-9]{4})-([0-9]{2})-([0-9]{2})")
def decoder_ok(v):
"""§4.2: `builtin:<crate>@<version>` as jwp-receipts §2.4.12 writes one, or
`platform:<interface>`."""
return _DEC_BUILTIN.fullmatch(v) is not None or _DEC_PLATFORM.fullmatch(v) is not None
def date_ok(v):
"""`YYYY-MM-DD`, a day its month has in its year (proleptic Gregorian)."""
m = _DATE.fullmatch(v)
if not m:
return False
y, mo, d = (int(g) for g in m.groups())
if not 1 <= mo <= 12:
return False
leap = y % 4 == 0 and (y % 100 != 0 or y % 400 == 0)
days = [31, 29 if leap else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][mo - 1]
return 1 <= d <= days
def is_hex(v, n):
return type(v) is str and len(v) == 2 * n and all(c in "0123456789abcdef" for c in v)
def utf8_ok(s):
try:
s.encode("utf-8")
return True
except UnicodeEncodeError:
return False
def fits(v, s):
if s == INT:
return type(v) is int and 0 <= v <= MAX
if s == STR:
return type(v) is str and utf8_ok(v)
if s == HEX32:
return is_hex(v, 32)
if s == HEX64:
return is_hex(v, 64)
if s == DECODER:
return type(v) is str and decoder_ok(v)
if s == DATE:
return type(v) is str and date_ok(v)
if s == FABRIC_LIST:
# §7 step 1: every member one of energy-measurement §9.1's fabrics, none twice.
return type(v) is list and all(type(x) is str and x in FABRIC_TERMS for x in v) and len(set(v)) == len(v)
tag = s[0]
if tag == "null":
return v is None or fits(v, s[1])
if tag == "enum":
return type(v) is str and v in s[1]
if tag == "const":
return type(v) is type(s[1]) and v == s[1]
if tag == "arr":
return type(v) is list and all(fits(x, s[1]) for x in v)
if tag == "pair":
return type(v) is list and len(v) == 2 and all(fits(x, s[1]) for x in v)
if tag == "obj":
return (isinstance(v, dict) and not getattr(v, "dup", False) and set(v) == set(s[1])
and all(fits(v[k], t) for k, t in s[1].items()))
raise AssertionError(s)
SUMMARY = obj({"n": INT, "mean_uw": INT, "sd_uw": INT, "live_intervals": INT, "longest_live_run": INT})
CLASS_MEMBERS = {
"joules_micro": INT,
"energy_provenance": nul(STR),
"energy_uncertainty": nul(obj({"relative_ppm": INT, "window_us": INT})),
"energy_counter_filtering": nul(STR),
"energy_calibration_ref": nul(STR),
}
COVERAGE = nul(enum("Whole", "Partial"))
UNIT = enum("image", "frame", "content-ms", "byte")
PATH = enum("software", "hardware")
ROW = obj(dict({
"capability": STR, "path": PATH, "decoder": DECODER, "profile": nul(enum(*MINIMUM_US)), "fabrics": FABRIC_LIST,
"coverage": COVERAGE, "unit": UNIT, "units": INT, "width": nul(INT), "height": nul(INT), "workers": INT,
"status": enum("figure", "relative", "unmetered", "absent"), "reason": nul(enum(*ROW_REASONS)),
"rounds": arr(obj({"idle": SUMMARY, "busy": SUMMARY, "window_us": INT, "completions": INT})),
"median": nul(INT), "range": nul(pair(INT)),
}, **CLASS_MEMBERS))
SCHEMA = {
TABLE: obj({
"wai_sink_table": const(1), "signer": HEX32, "procedure": const("wai-sink-table/1"),
"procedure_sha256": HEX32, "readings_sha256": HEX32,
"machine": obj({"os": STR, "arch": STR, "processor": STR, "cores": INT, "memory_gib": INT}),
"build": obj({"profile": enum("release", "debug"), "toolchain": nul(STR), "target": nul(STR)}),
"measured": DATE, "rounds": INT, "sample_us": INT,
"counters": arr(obj({"profile": enum(*MINIMUM_US), "status": enum(*COUNTER_STATUS), "detail": STR})),
"rows": arr(ROW), "sig": HEX64,
}),
SEGMENT: obj(dict({
"wai_sink_segment": const(1), "signer": HEX32, "session": HEX32, "stream": HEX32, "segment": INT,
"prev": nul(HEX32), "object": HEX32, "capability": STR, "path": PATH, "decoder": DECODER, "unit": UNIT,
"units": INT, "width": nul(INT), "height": nul(INT), "media_us": INT,
"method": enum("measured", "table", "estimator", "unmetered"), "profile": nul(enum(*PROFILES)),
"fabrics": FABRIC_LIST, "coverage": COVERAGE,
"bracket": nul(obj({"idle": SUMMARY, "busy": SUMMARY, "window_us": INT, "sample_us": INT})),
"table": nul(obj({"id": HEX32, "row": INT, "per_completion_uj": INT, "units_per_completion": INT})),
"estimator": nul(obj({"method": const(CPU_EST), "cpu_us": INT, "active_mw": INT, "basis": STR,
"relative_ppm": INT})),
"reason": nul(enum(*UNMETERED_REASONS)), "sig": HEX64,
}, **CLASS_MEMBERS)),
SESSION: obj({
"wai_sink_session": const(1), "signer": HEX32, "session": HEX32,
"streams": arr(obj({"stream": HEX32, "segments": INT, "last": HEX32})),
"media_us": INT, "presented_us": INT,
"display": nul(obj({"method": const(DISPLAY_EST), "panel_class": enum("backlit", "emissive"),
"on_mode_mw": INT, "reference_nits": INT, "nits": INT, "basis": STR,
"relative_ppm": INT})),
"hops": arr(obj(dict({
"role": INT,
"unmetered": nul(enum(*MARKER_REASONS)),
"coverage": COVERAGE,
"source": nul(obj({"kind": enum("live-metering-hop", "other"), "record": HEX32, "hop_joules": INT,
"hop_class": STR, "share_num": INT, "share_den": INT})),
}, **CLASS_MEMBERS))),
"sig": HEX64,
}),
}
_REGISTRY = None
def registry():
"""§4.2: `capability` is a capability the registry lists (registry/capabilities.json)."""
global _REGISTRY
if _REGISTRY is None:
with open(os.path.join(HERE, "..", "registry", "capabilities.json"), encoding="utf-8") as f:
_REGISTRY = frozenset(c["capability"] for c in json.load(f)["capabilities"])
return _REGISTRY
def unit_ok(x):
"""§7 step 1: `width` and `height` at least 1 for `image` and `frame`, `null` otherwise;
`units` at least 1."""
if x["unit"] in ("image", "frame"):
wh = type(x["width"]) is int and x["width"] >= 1 and type(x["height"]) is int and x["height"] >= 1
else:
wh = x["width"] is None and x["height"] is None
return wh and x["units"] >= 1
def shape(rec, kind):
"""§7 step 1 (`record_malformed`)."""
first = KINDS[kind][0]
need(isinstance(rec, dict), "record_malformed", "the record is not a JSON object")
need(not getattr(rec, "dup", False), "record_malformed", "a member name repeats")
need(first in rec, "record_malformed", "the record has no `%s`, its first member (§3)" % first)
need(fits(rec, SCHEMA[kind]), "record_malformed", "a member is missing, extra, or not of its type (§7 step 1)")
if kind == TABLE:
for i, row in enumerate(rec["rows"]):
need(unit_ok(row), "record_malformed", "row %d: width, height or units (§7 step 1)" % i)
need(row["capability"] in registry(), "record_malformed",
"row %d: `%s` is not a capability the registry lists (§4.2)" % (i, row["capability"]))
keys = [(c["profile"].encode("utf-8"), c["detail"].encode("utf-8")) for c in rec["counters"]]
need(all(a <= b for a, b in zip(keys, keys[1:])), "record_malformed",
"`counters` is not in ascending order of (profile, detail) (§4.1)")
elif kind == SEGMENT:
need(unit_ok(rec), "record_malformed", "width, height or units (§7 step 1)")
need(rec["capability"] in registry(), "record_malformed",
"`%s` is not a capability the registry lists (§4.2, §5.1)" % rec["capability"])
need(rec["media_us"] >= 1, "record_malformed", "`media_us` is below 1 (§5.1)")
need((rec["prev"] is None) == (rec["segment"] == 0), "record_malformed",
"`prev` is not null exactly when `segment` is 0 (§5.1, §7 step 1)")
else:
keys = [s["stream"] for s in rec["streams"]]
need(len(keys) >= 1 and all(a < b for a, b in zip(keys, keys[1:])), "record_malformed",
"`streams` is empty or not in strictly ascending order of `stream` (§6.1)")
roles = [h["role"] for h in rec["hops"]]
need(all(1 <= r <= 4 for r in roles) and all(a < b for a, b in zip(roles, roles[1:])), "record_malformed",
"a hop's `role` is not 1 to 4, or the entries are not in strictly ascending order of `role` (§6.1, §7 step 1)")
# ---------------------------------------------------------------- §3: signature and identity
def body_of(rec):
return {k: v for k, v in rec.items() if k != "sig"}
_SIG_CACHE = {}
def sig_ok(pk, msg, sig):
key = (pk, sha(msg), sig)
if key not in _SIG_CACHE:
_SIG_CACHE[key] = ED.verify(pk, msg, sig) is None
return _SIG_CACHE[key]
def check_signature(rec, kind):
"""§7 step 2: `sig` over `domain ‖ JCS(body)` under `signer`."""
msg = KINDS[kind][1] + jcs(body_of(rec))
need(sig_ok(bytes.fromhex(rec["signer"]), msg, bytes.fromhex(rec["sig"])), "signature_invalid",
"the signature does not verify under `signer` (§3, SPEC §7)")
def identity(rec, kind):
"""§3: SHA-256(id-domain ‖ JCS(body) ‖ signature bytes)."""
return sha(KINDS[kind][2], jcs(body_of(rec)), bytes.fromhex(rec["sig"]))
def try_identity(rec, kind):
try:
if isinstance(rec, dict) and is_hex(rec.get("sig"), 64):
return identity(rec, kind).hex()
except (ValueError, TypeError, AttributeError):
pass
return None
# ---------------------------------------------------------------- §7 step 3: classes
def _trimmed_empty(s):
return all(ord(c) in WHITE_SPACE for c in s)
def check_class(x, where):
"""One class beside its figure, as §2 writes it (jwp-receipts §2.4.5)."""
prov, unc = x["energy_provenance"], x["energy_uncertainty"]
filt, ref, j = x["energy_counter_filtering"], x["energy_calibration_ref"], x["joules_micro"]
need(prov != "HwShunt", "hwshunt_forbidden", "%s: the class is HwShunt (energy-measurement §2.6)" % where)
need((prov is None) == (j == 0), "unmetered_as_zero",
"%s: %s beside a figure of %d (energy-measurement §2)" % (where, prov or "no class", j))
if prov is None:
need(unc is None and filt is None and ref is None, "energy_class_invalid",
"%s: evidence without a class (energy-measurement §2.7)" % where)
else:
need(prov in CLASSES, "energy_class_invalid", "%s: `%s` is not a class of energy-measurement §2" % (where, prov))
if prov == "OnChipCounter":
ok = unc is not None and filt in FILTERING and ref is None
elif prov == "CalibratedInstrument":
ok = unc is not None and filt is None and type(ref) is str and not _trimmed_empty(ref)
else:
ok = unc is None and filt is None and ref is None
need(ok, "energy_class_invalid", "%s: the evidence is not exactly %s's (energy-measurement §2.7)" % (where, prov))
if unc is not None:
need(unc["relative_ppm"] >= 1 and unc["window_us"] >= 1, "energy_class_invalid",
"%s: an `energy_uncertainty` member of 0 (energy-measurement §2.3)" % where)
need(unc["relative_ppm"] <= U32, "energy_class_invalid",
"%s: `relative_ppm` wider than its u32 encoding (energy-measurement §2.7, jwp-receipts §2.4.5)" % where)
need(j * unc["relative_ppm"] >= FLOOR, "energy_class_invalid",
"%s: %d x %d is below the resolution floor 288 676 (energy-measurement §2.3)"
% (where, j, unc["relative_ppm"]))
def check_hop_class(label, where):
need(label != "HwShunt", "hwshunt_forbidden", "%s: the hop's class is HwShunt (§6.4)" % where)
need(label in CLASSES, "energy_class_invalid", "%s: `hop_class` %r is not a label of a class (§7 step 3)" % (where, label))
# ---------------------------------------------------------------- the integer forms
def least_sq(k, p):
"""The least integer x ≥ 0 with x² · k ≥ p, or None when there is none (k = 0 < p)."""
if p <= 0:
return 0
if k <= 0:
return None
x = math.isqrt(p // k)
while x * x * k < p:
x += 1
return x
def ceil_div(a, b):
return -(-a // b)
def figure_of(m, t, wn, wd):
"""energy-measurement §6.2: F = ⌊(2·M·T·Wd + 10⁶·Wn) / (2·10⁶·Wn)⌋."""
return (2 * m * t * wd + 10 ** 6 * wn) // (2 * 10 ** 6 * wn)
def least_p(ni, si, nb, sb, m, t, wn, wd, n, f):
"""energy-measurement §6.2: the least p with p² · K ≥ P."""
k = 12 * ni * nb * wn ** 4 * f * f
p = (12 * wn * wn * t * t * wd * wd * (si * si * nb + sb * sb * ni)
+ 4 * ni * nb * m * m * t * t * wd * wd * n * n
+ 10 ** 12 * ni * nb * wn ** 4)
return least_sq(k, p)
def live(s, span):
"""§4.5 rule 2 (energy-measurement §3.1, §6.2): `sd_uw` above 0, at least 5 live
intervals, a run of at least 2, `5 · live ≥ 4 · n`, a span of at least 300 ms."""
return (s["sd_uw"] > 0 and s["live_intervals"] >= 5 and s["longest_live_run"] >= 2
and 5 * s["live_intervals"] >= 4 * s["n"] and span >= LIVE_SPAN_US)
def summary_of(intervals):
"""§4.3: a bracket's summary from its intervals [d nJ, t µs]."""
n = len(intervals)
ps = [(2000 * d + t) // (2 * t) for d, t in intervals]
s1, s2 = sum(ps), sum(p * p for p in ps)
best = run = 0
for d, _ in intervals:
run = run + 1 if d > 0 else 0
best = max(best, run)
return {"n": n, "mean_uw": (2 * s1 + n) // (2 * n) if n else 0,
"sd_uw": least_sq(n * (n - 1), n * s2 - s1 * s1) if n >= 2 else 0,
"live_intervals": sum(1 for d, _ in intervals if d > 0), "longest_live_run": best}
def estimate_cpu(cpu_us, active_mw):
"""energy-measurement §9.4."""
return (2 * cpu_us * active_mw + 1000) // 2000
def estimate_display(on_mode_mw, nits, presented_us, reference_nits):
"""energy-measurement §9.5."""
return (2 * on_mode_mw * nits * presented_us + 1000 * reference_nits) // (2000 * reference_nits)
def share_of(hop_joules, num, den):
"""§6.4."""
return (2 * hop_joules * num + den) // (2 * den)
def table_figure(per_completion, units, per):
"""§5.2 `table`."""
return (2 * per_completion * units + per) // (2 * per)
# ---------------------------------------------------------------- §4.5: a round and a row
def round_figure(rd, workers, minimum, sample_us):
"""§4.5: the first rule a round breaks, or (F, p, M, s_idle). The bracket opened from
rest: Wn = 2C + N, Wd = 2, N the row's workers."""
i, b = rd["idle"], rd["busy"]
t, c = rd["window_us"], rd["completions"]
if i["n"] < 2 or b["n"] < 2:
return "too_few_samples"
if not (live(i, i["n"] * sample_us) and live(b, t)):
return "rail_not_live"
if t < minimum:
return "window_short"
if c < 1:
return "empty_burst"
if b["mean_uw"] <= i["mean_uw"]:
return "no_marginal"
m = b["mean_uw"] - i["mean_uw"]
if m < i["sd_uw"]:
return "below_attribution_floor"
wn = 2 * c + workers
f = figure_of(m, t, wn, 2)
if f < 1:
return "figure_zero"
if f > MAX:
return "not_declarable"
p = least_p(i["n"], i["sd_uw"], b["n"], b["sd_uw"], m, t, wn, 2, workers, f)
if p is None or p > U32:
return "not_declarable"
return (f, p, m, i["sd_uw"])
def row_outcome(row, sample_us):
"""§4.5 *The row*: its status and reason, and for a figure its median, range, F, p, q
and window."""
minimum = MINIMUM_US[row["profile"]]
figs = []
for r, rd in enumerate(row["rounds"]):
got = round_figure(rd, row["workers"], minimum, sample_us)
if isinstance(got, str):
return {"status": "unmetered", "reason": got, "round": r}
figs.append((got[0], r, got))
order = sorted(figs, key=lambda x: (x[0], x[1]))
_, med, (f, p, m, si) = order[len(order) // 2]
if m >= 10 * si:
status, reason = "figure", None
elif m >= 3 * si:
status, reason = "relative", None
else:
return {"status": "unmetered", "reason": "noisy", "round": med}
lo, hi = min(x[0] for x in figs), max(x[0] for x in figs)
q = least_sq(12 * f * f, 10 ** 12 * (hi - lo) ** 2)
if max(p, q) > U32:
return {"status": "unmetered", "reason": "not_declarable", "round": med}
return {"status": status, "reason": reason, "median": med, "range": [lo, hi], "F": f, "p": p, "q": q,
"window": row["rounds"][med]["window_us"]}
def power_of_two(n):
return n >= 1 and n & (n - 1) == 0
def marker(x):
"""The unmetered marker: `joules_micro` 0 and the four class members `null` (§2)."""
return (x["joules_micro"] == 0 and x["energy_provenance"] is None and x["energy_uncertainty"] is None
and x["energy_counter_filtering"] is None and x["energy_calibration_ref"] is None)
def row_key(row):
"""§4.1: (capability, path, decoder, profile), strings by their bytes, a null profile first."""
return (row["capability"].encode("utf-8"), row["path"].encode("utf-8"), row["decoder"].encode("utf-8"),
(0, b"") if row["profile"] is None else (1, row["profile"].encode("utf-8")))
# ---------------------------------------------------------------- §7 step 4: the decode table
def readings_bytes_of(readings):
"""§4.3: the readings file is the JCS form of its object, so one held inline as an
object is digested as its JCS bytes."""
try:
return jcs(readings)
except (ValueError, TypeError, AttributeError):
return None
def _intervals_ok(v):
return type(v) is list and all(
type(x) is list and len(x) == 2 and type(x[0]) is int and type(x[1]) is int
and 0 <= x[0] <= MAX and 1 <= x[1] <= MAX for x in v)
def check_readings(rec, readings, raw):
"""§4.3, §7 step 4's last bullet (`table_readings_mismatch`)."""
why = "the readings file (§4.3)"
need(raw is not None and sha(raw).hex() == rec["readings_sha256"], "table_readings_mismatch",
"the readings file's SHA-256 is not `readings_sha256` (§4.1)")
need(isinstance(readings, dict) and not getattr(readings, "dup", False)
and set(readings) == {"wai_sink_readings", "rows"} and type(readings["wai_sink_readings"]) is int
and readings["wai_sink_readings"] == 1 and type(readings["rows"]) is list,
"table_readings_mismatch", why + " does not read")
need(len(readings["rows"]) == len(rec["rows"]), "table_readings_mismatch",
"the readings file has %d entries for %d rows" % (len(readings["rows"]), len(rec["rows"])))
for i, (e, row) in enumerate(zip(readings["rows"], rec["rows"])):
need(isinstance(e, dict) and not getattr(e, "dup", False) and set(e) == {"capability", "path", "decoder", "profile", "rounds"}
and type(e["rounds"]) is list, "table_readings_mismatch", "entry %d does not read" % i)
need(e["capability"] == row["capability"] and e["path"] == row["path"] and e["decoder"] == row["decoder"]
and e["profile"] == row["profile"]
and (e["profile"] is None) == (row["profile"] is None),
"table_readings_mismatch", "entry %d does not name row %d" % (i, i))
need(len(e["rounds"]) == len(row["rounds"]), "table_readings_mismatch",
"entry %d has %d rounds, row %d %d" % (i, len(e["rounds"]), i, len(row["rounds"])))
for r, (er, rr) in enumerate(zip(e["rounds"], row["rounds"])):
need(isinstance(er, dict) and not getattr(er, "dup", False) and set(er) == {"idle", "busy", "completions"}
and _intervals_ok(er["idle"]) and _intervals_ok(er["busy"]) and type(er["completions"]) is int,
"table_readings_mismatch", "row %d round %d's readings do not read" % (i, r))
got = {"idle": summary_of(er["idle"]), "busy": summary_of(er["busy"]),
"window_us": sum(t for _, t in er["busy"]), "completions": er["completions"]}
for k in ("idle", "busy", "window_us", "completions"):
need(got[k] == rr[k], "table_readings_mismatch",
"row %d round %d: %s is %r from the readings, the table states %r (§4.3)" % (i, r, k, got[k], rr[k]))
def verify_table(rec, readings=None, raw=None, held_readings=False):
"""§7 steps 1–4 for a decode table; its identity. `held_readings` says the verifier holds
the readings file (`readings`, digested as `raw`)."""
shape(rec, TABLE)
check_signature(rec, TABLE)
for i, row in enumerate(rec["rows"]):
check_class(row, "row %d" % i)
n = rec["rounds"]
need(n % 2 == 1 and n >= 7, "table_rounds_invalid", "`rounds` is %d: odd and at least 7 (§4.1)" % n)
for i, row in enumerate(rec["rows"]):
need(row["status"] == "absent" or len(row["rounds"]) == n, "table_rounds_invalid",
"row %d has %d rounds, not %d" % (i, len(row["rounds"]), n))
keys = [row_key(r) for r in rec["rows"]]
for i in range(1, len(keys)):
need(keys[i - 1] < keys[i], "table_row_order", "row %d is not above row %d (§4.1)" % (i, i - 1))
live_profiles = {c["profile"] for c in rec["counters"] if c["status"] == "live"}
for i, row in enumerate(rec["rows"]):
where = "row %d (%s %s %s)" % (i, row["capability"], row["path"], row["profile"])
# its status and reason
out = None
if row["status"] == "absent":
need(row["reason"] in ABSENT_REASONS and row["rounds"] == [] and row["workers"] == 0
and (row["profile"] is None) == (row["reason"] == "no_decoder") and row["fabrics"] == []
and row["coverage"] is None and row["median"] is None and row["range"] is None,
"table_row_status", "%s: not an absent row (§4.5, §7 step 4)" % where)
else:
need(row["profile"] is not None, "table_row_status", "%s: no profile, and not absent for no_decoder" % where)
need(power_of_two(row["workers"]), "table_row_status", "%s: workers %d not a power of two" % (where, row["workers"]))
out = row_outcome(row, rec["sample_us"])
need((row["status"], row["reason"]) == (out["status"], out["reason"]), "table_row_status",
"%s: states %s/%s, its rounds give %s/%s (round %s)"
% (where, row["status"], row["reason"], out["status"], out["reason"], out.get("round")))
if row["status"] in ("absent", "unmetered"):
need(marker(row), "table_row_status", "%s: an %s row without the unmetered marker (§7 step 4)" % (where, row["status"]))
if row["profile"] is not None:
is_live = row["profile"] in live_profiles
need(is_live == (not (row["status"] == "absent" and row["reason"] == "no_counter")), "table_row_status",
"%s: its profile is %slive in `counters`" % (where, "" if is_live else "not "))
# its figure
if row["status"] != "absent":
need(row["fabrics"] == FABRICS[row["profile"]], "table_row_figure",
"%s: fabrics %r, not its profile's %r (§4.2)" % (where, row["fabrics"], FABRICS[row["profile"]]))
need(row["coverage"] == "Partial", "table_row_figure", "%s: coverage %r, not Partial (§4.5)" % (where, row["coverage"]))
if row["status"] in ("figure", "relative"):
need(row["median"] == out["median"], "table_row_figure",
"%s: median %r, its rounds give %d" % (where, row["median"], out["median"]))
need(row["range"] == out["range"], "table_row_figure",
"%s: range %r, its rounds give %r" % (where, row["range"], out["range"]))
need(row["joules_micro"] == out["F"], "table_row_figure",
"%s: joules_micro %d, the median's figure is %d" % (where, row["joules_micro"], out["F"]))
need(row["energy_provenance"] == "CalibratedInstrument" or (row["energy_provenance"] == "OnChipCounter"
and row["energy_counter_filtering"] == "Unknown"), "table_row_figure",
"%s: class %s/%s, not OnChipCounter with filtering Unknown or CalibratedInstrument"
% (where, row["energy_provenance"], row["energy_counter_filtering"]))
need(row["energy_uncertainty"]["window_us"] == out["window"], "table_row_figure",
"%s: window_us %d, the median round's is %d" % (where, row["energy_uncertainty"]["window_us"], out["window"]))
else:
need(row["median"] is None and row["range"] is None, "table_row_figure",
"%s: an unmetered row with a median or range" % where)
# its declaration
if row["status"] in ("figure", "relative"):
least = max(out["p"], out["q"])
need(row["energy_uncertainty"]["relative_ppm"] >= least, "table_row_declaration",
"%s: relative_ppm %d below max(p %d, q %d)" % (where, row["energy_uncertainty"]["relative_ppm"], out["p"], out["q"]))
if held_readings: # §7 step 4: once every row has passed
check_readings(rec, readings, raw)
return identity(rec, TABLE)
# ---------------------------------------------------------------- §7 step 5: the segment receipt
def held_tables(tables):
out = {}
for t in tables or []:
h = try_identity(t, TABLE)
if h is not None:
out.setdefault(h, t)
return out
def verify_segment(rec, tables):
"""§7 steps 1–5 for one segment receipt (not its chain); its identity. `tables` is the
list of decode tables the verifier holds, found by identity."""
shape(rec, SEGMENT)
check_signature(rec, SEGMENT)
check_class(rec, "the segment")
m, prov, prof = rec["method"], rec["energy_provenance"], rec["profile"]
has = tuple(rec[k] is not None for k in ("bracket", "table", "estimator"))
if m == "measured":
ok = has == (True, False, False) and rec["reason"] is None and prof in MINIMUM_US and prov in HARDWARE
elif m == "table":
ok = has == (False, True, False) and rec["reason"] is None and prof in MINIMUM_US and prov in ("ModelBased", "Estimator")
elif m == "estimator":
ok = has == (False, False, True) and rec["reason"] is None and prof == CPU_EST and prov == "Estimator"
else:
ok = (has == (False, False, False) and prof is None and rec["coverage"] is None and rec["fabrics"] == []
and marker(rec) and rec["reason"] in UNMETERED_REASONS)
if ok and m != "unmetered":
ok = rec["fabrics"] == FABRICS[prof] and rec["coverage"] == "Partial" and rec["reason"] is None
need(ok, "segment_method_class", "its members or class do not fit the method `%s` (§5.2, §7 step 5)" % m)
if m == "measured":
b = rec["bracket"]
i, bu, t = b["idle"], b["busy"], b["window_us"]
need(live(i, i["n"] * b["sample_us"]) and live(bu, t), "segment_rail_not_live",
"a bracket is not live (§4.5 rule 2, §5.2)")
need(t >= MINIMUM_US[prof], "segment_window_short", "window %d below %s's minimum" % (t, prof))
mm = bu["mean_uw"] - i["mean_uw"]
need(mm >= i["sd_uw"], "segment_below_floor", "M %d below the idle sd %d" % (mm, i["sd_uw"]))
f = figure_of(mm, t, 1, 1)
need(rec["joules_micro"] == f and f >= 1 and rec["energy_uncertainty"]["window_us"] == t,
"segment_figure_mismatch", "joules_micro %d window_us %d; the bracket gives F %d over T %d"
% (rec["joules_micro"], rec["energy_uncertainty"]["window_us"], f, t))
p = least_p(i["n"], i["sd_uw"], bu["n"], bu["sd_uw"], mm, t, 1, 1, 0, f)
need(p is not None and rec["energy_uncertainty"]["relative_ppm"] >= p, "segment_declaration_below",
"relative_ppm %d below p %s" % (rec["energy_uncertainty"]["relative_ppm"], p))
elif m == "table":
tb = rec["table"]
per = tb["units_per_completion"]
need(per >= 1 and rec["joules_micro"] == table_figure(tb["per_completion_uj"], rec["units"], per)
and rec["joules_micro"] >= 1, "segment_table_mismatch", "the figure is not the formula's (§5.2)")
held = held_tables(tables).get(tb["id"])
if held is not None:
try:
verify_table(held)
except Refused as e:
raise Refused("segment_table_mismatch", "the held table %s does not verify (%s)" % (tb["id"], e.reason))
need(prov == ("ModelBased" if held["signer"] == rec["signer"] else "Estimator"), "segment_table_mismatch",
"class %s; the table's signer is %sthe receipt's (§5.2)" % (prov, "" if held["signer"] == rec["signer"] else "not "))
rows = held["rows"]
need(tb["row"] < len(rows), "segment_table_mismatch", "row %d is not in the table" % tb["row"])
row = rows[tb["row"]]
need(row["status"] == "figure", "segment_table_mismatch", "row %d's status is %s" % (tb["row"], row["status"]))
for k in ("capability", "path", "decoder", "profile", "unit", "width", "height", "fabrics", "coverage"):
need(row[k] == rec[k], "segment_table_mismatch", "`%s` is not row %d's" % (k, tb["row"]))
need(tb["per_completion_uj"] == row["joules_micro"] and per == row["units"], "segment_table_mismatch",
"per_completion_uj or units_per_completion is not row %d's" % tb["row"])
elif m == "estimator":
e = rec["estimator"]
est = estimate_cpu(e["cpu_us"], e["active_mw"])
need(rec["joules_micro"] == est and est >= 1 and len(e["basis"]) > 0 and e["relative_ppm"] >= 1,
"segment_estimator_mismatch", "joules_micro %d; E is %d (energy-measurement §9.4)" % (rec["joules_micro"], est))
return identity(rec, SEGMENT)
def chain_ok(receipts, ids):
"""§5.3: one session, signer and stream throughout; segments 0 to k in order; each
`prev` the identity of the receipt before it, and `null` for segment 0."""
if not receipts:
return "no receipt"
r0 = receipts[0]
for k, r in enumerate(receipts):
if (r["session"], r["signer"], r["stream"]) != (r0["session"], r0["signer"], r0["stream"]):
return "receipt %d names another session, signer or stream" % k
if r["segment"] != k:
return "receipt %d is segment %d" % (k, r["segment"])
if r["prev"] != (None if k == 0 else ids[k - 1]):
return "receipt %d's prev is not the identity of the receipt before it" % k
return None
def verify_chain(receipts, tables):
"""A `chain` case: each receipt by steps 1–5, then §5.3; the last receipt's identity."""
ids = [verify_segment(r, tables).hex() for r in receipts]
bad = chain_ok(receipts, ids)
need(bad is None, "segment_chain_broken", bad)
return bytes.fromhex(ids[-1])
# ---------------------------------------------------------------- §7 step 6: the session receipt
def expected_decode(segments):
"""§6.3 *sink_decode* from the segment receipts."""
metered = [s for s in segments if s["method"] != "unmetered"]
if not metered:
return {"status": "absent", "reason": "unmetered"}
total = sum(s["joules_micro"] for s in metered)
weakest = max((s["energy_provenance"] for s in metered), key=lambda c: RANK[c])
whole = len(metered) == len(segments) and all(s["coverage"] == "Whole" for s in metered)
out = {"status": "figure", "reason": None, "joules_micro": total, "coverage": "Whole" if whole else "Partial",
"energy_counter_filtering": None, "energy_calibration_ref": None, "window_us": None, "bound": None}
if weakest not in HARDWARE:
out["energy_provenance"] = weakest
return out
refs = {s["energy_calibration_ref"] for s in metered}
if all(s["energy_provenance"] == "CalibratedInstrument" for s in metered) and len(refs) == 1:
out["energy_provenance"], out["energy_calibration_ref"] = "CalibratedInstrument", refs.pop()
else:
filt = [s["energy_counter_filtering"] for s in metered]
out["energy_provenance"] = "OnChipCounter"
every_off = all(s["energy_provenance"] == "OnChipCounter" and s["energy_counter_filtering"] == "Off" for s in metered)
out["energy_counter_filtering"] = "On" if "On" in filt else "Off" if every_off else "Unknown"
out["window_us"] = max(s["energy_uncertainty"]["window_us"] for s in metered)
out["bound"] = ceil_div(sum(s["joules_micro"] * s["energy_uncertainty"]["relative_ppm"] for s in metered), total)
return out
def check_hop(name, part, held_hops):
"""§6.4 for the `origin` or `relay` part (`split_hop_mismatch`): the sole-user rule, the
figure, the class and evidence, and, holding the record, the record."""
if part["energy_provenance"] is None: # the marker: no figure to check
return
src = part["source"]
hj, num, den = src["hop_joules"], src["share_num"], src["share_den"]
need(hj >= 1 and 1 <= num <= den, "split_hop_mismatch", "%s: hop_joules or the share is out of range" % name)
need(100 * num >= 99 * den, "split_hop_mismatch",
"%s: %d of %d is below the sole user's 99%%; a shared hop is absent for hop_shared (§6.4)" % (name, num, den))
j = share_of(hj, num, den)
need(j >= 1 and part["joules_micro"] == j, "split_hop_mismatch",
"%s: joules_micro %d, §6.4 gives %d" % (name, part["joules_micro"], j))
need(part["energy_provenance"] == src["hop_class"], "split_hop_mismatch",
"%s: class %s, the hop's is %s (§6.4)" % (name, part["energy_provenance"], src["hop_class"]))
if src["kind"] != "live-metering-hop" or src["record"] not in held_hops:
return
b = held_hops[src["record"]]
try:
x = LMV.read_hop(b, b[5:37])
except LMV.Refuse as e:
raise Refused("split_hop_mismatch", "%s: the hop record does not read (%s, live-metering §3.6)" % (name, e.reason))
need(x["digest"].hex() == src["record"], "split_hop_mismatch", "%s: the record's digest is not `record`" % name)
need(x["joules"] == hj, "split_hop_mismatch", "%s: the record's joules %d, hop_joules %d" % (name, x["joules"], hj))
label = LMV.LABELS.get(x["class"][0]) if x["class"] not in (None, LMV.INVALID) else None
need(label == src["hop_class"], "split_hop_mismatch", "%s: the record's class is %s" % (name, label))
c = x["class"]
if c[0] == 4:
ev = ({"relative_ppm": c[1], "window_us": c[2]}, FILTER_BYTE[c[3]], None)
elif c[0] == 5:
ev = ({"relative_ppm": c[1], "window_us": c[2]}, None, c[3])
else:
ev = (None, None, None)
got = (part["energy_uncertainty"], part["energy_counter_filtering"], part["energy_calibration_ref"])
need(got == ev, "split_hop_mismatch", "%s: the part's evidence is not the record's" % name)
need(sum(x["sub"]) == den, "split_hop_mismatch",
"%s: share_den %d, the record's subscriber-microseconds sum to %d" % (name, den, sum(x["sub"])))
def verify_session(rec, segments, tables, held_hops):
"""§7 steps 1–3 and 6 for a session receipt; its identity."""
shape(rec, SESSION)
check_signature(rec, SESSION)
for h in rec["hops"]:
where = "the %s entry" % ROLE_NAME[h["role"]]
check_class(h, where)
if h["source"] is not None:
check_hop_class(h["source"]["hop_class"], where + "'s source")
by_role = {h["role"]: h for h in rec["hops"]}
need(SINK_DECODE in by_role and ORIGIN in by_role, "split_part_invalid",
"the sink decode and the origin always have an entry (§6.2)")
need((DISPLAY in by_role) == (rec["presented_us"] > 0), "split_part_invalid",
"the display has an entry exactly when presented_us is above 0 (§6.2); presented_us %d" % rec["presented_us"])
for h in rec["hops"]:
role = h["role"]
if h["energy_provenance"] is not None: # a figure (step 3: a class beside a figure of at least 1)
cov = h["coverage"] in ("Whole", "Partial") if role == SINK_DECODE else h["coverage"] == ROLE_COVERAGE[role]
ok = h["unmetered"] is None and h["joules_micro"] >= 1 and cov and (h["source"] is not None) == (role in (ORIGIN, RELAY))
else:
ok = marker(h) and h["coverage"] is None and h["source"] is None and h["unmetered"] in ROLE_REASONS[role]
need(ok, "split_part_invalid", "the %s entry is neither a figure nor a marker with its reason (§6.2)" % ROLE_NAME[role])
d = rec["display"]
if d is not None:
need(d["on_mode_mw"] >= 1 and d["reference_nits"] >= 1 and d["relative_ppm"] >= 1 and len(d["basis"]) > 0,
"split_display_mismatch", "the display's declaration is out of range (§6.3)")
dp = by_role.get(DISPLAY)
if dp is not None:
if d is None:
need(dp["energy_provenance"] is None and dp["unmetered"] == "display_undeclared", "split_display_mismatch",
"no display declared, and the entry is not the marker display_undeclared (§6.3)")
else:
e = estimate_display(d["on_mode_mw"], d["nits"], rec["presented_us"], d["reference_nits"])
if e >= 1:
need(dp["energy_provenance"] == "Estimator" and dp["joules_micro"] == e, "split_display_mismatch",
"the display entry is not the Estimator figure %d (energy-measurement §9.5)" % e)
else:
need(dp["energy_provenance"] is None and dp["unmetered"] == "unmetered", "split_display_mismatch",
"E is 0, and the display entry is not the marker unmetered (§6.3)")
for role in (ORIGIN, RELAY):
if role in by_role:
check_hop(ROLE_NAME[role], by_role[role], held_hops)
if segments:
ids = []
for k, s in enumerate(segments):
try:
ids.append(verify_segment(s, tables).hex())
except Refused as e:
raise Refused("session_streams_mismatch", "segment receipt %d is refused %s (%s)" % (k, e.reason, e.why))
need(s["session"] == rec["session"] and s["signer"] == rec["signer"], "session_streams_mismatch",
"segment receipt %d names another session or signer" % k)
by_stream = {}
for s, h in zip(segments, ids):
by_stream.setdefault(s["stream"], []).append((s, h))
listed = {st["stream"]: st for st in rec["streams"]}
need(set(by_stream) == set(listed), "session_streams_mismatch", "the streams are not the receipts' streams")
for stream, items in by_stream.items():
bad = chain_ok([s for s, _ in items], [h for _, h in items])
need(bad is None, "session_streams_mismatch", "stream %s: %s" % (stream, bad))
need(listed[stream]["segments"] == len(items) and listed[stream]["last"] == items[-1][1],
"session_streams_mismatch", "stream %s: its count or last identity" % stream)
total = sum(s["media_us"] for s in segments)
need(rec["media_us"] == total, "session_streams_mismatch", "media_us %d, the receipts sum to %d" % (rec["media_us"], total))
want, got = expected_decode(segments), by_role[SINK_DECODE]
if want["status"] == "absent":
ok = got["energy_provenance"] is None and got["unmetered"] == "unmetered"
else:
ok = (got["energy_provenance"] is not None and got["joules_micro"] == want["joules_micro"]
and got["energy_provenance"] == want["energy_provenance"]
and got["energy_counter_filtering"] == want["energy_counter_filtering"]
and got["energy_calibration_ref"] == want["energy_calibration_ref"]
and got["coverage"] == want["coverage"])
if ok and want["window_us"] is not None:
ok = (got["energy_uncertainty"]["window_us"] == want["window_us"]
and got["energy_uncertainty"]["relative_ppm"] >= want["bound"])
need(ok, "split_decode_mismatch", "the sink-decode entry is not what §6.3 gives: %r" % (want,))
return identity(rec, SESSION)
# ---------------------------------------------------------------- the corpus
def held_hops_of(case, doc):
out = {}
for d in case.get("hops") or []:
if d in (doc.get("hops") or {}):
try:
out[d] = bytes.fromhex(doc["hops"][d])
except (ValueError, TypeError):
pass
return out
def run_case(case, doc):
"""The outcome a case's inputs give: (outcome, identity hex or None, why)."""
subj, tables = case["subject"], case.get("tables") or []
try:
if subj == "table":
held = case.get("readings") is not None
ident = verify_table(case["record"], case.get("readings"),
readings_bytes_of(case["readings"]) if held else None, held)
elif subj == "segment":
ident = verify_segment(case["record"], tables)
elif subj == "chain":
ident = verify_chain(case["segments"], tables)
elif subj == "session":
ident = verify_session(case["record"], case.get("segments") or [], tables, held_hops_of(case, doc))
else:
return ("<subject %r>" % subj, None, "")
return ("accept", ident.hex(), "")
except Refused as e:
return (e.reason, None, e.why)
except (KeyError, TypeError, ValueError, AttributeError, IndexError) as e:
return ("<verifier error %s: %s>" % (type(e).__name__, e), None, "")
def check(doc, quiet=False, notes=None):
"""Every case against its stated outcome; the reasons refused. (fails, outcomes). What
may be deliberate in a vector (a hop record carried under a digest that is not its own,
which §6.4's digest rule refuses) goes to `notes`, not to the failures."""
fails, outcomes, seen = [], {}, set()
notes = [] if notes is None else notes
for k in ("wai_sink_energy_corpus", "keys", "hops", "cases"):
if k not in doc:
fails.append("the corpus has no `%s`" % k)
names = [c.get("name") for c in doc.get("cases", [])]
if len(set(names)) != len(names):
fails.append("two cases share a name")
for d in (doc.get("hops") or {}):
try:
b = bytes.fromhex(doc["hops"][d])
except (ValueError, TypeError):
fails.append("the hop record under %s is not hexadecimal" % d[:16])
continue
if LMV.given_digest(b).hex() != d:
notes.append("the hop record under %s has the digest %s" % (d[:16], LMV.given_digest(b).hex()[:16]))
for case in doc.get("cases", []):
name = case.get("name")
for d in case.get("hops") or []:
if d not in (doc.get("hops") or {}):
notes.append("%s: holds hop %s, which the corpus does not carry (read as not held)" % (name, d[:16]))
got, ident, why = run_case(case, doc)
outcomes[name] = (got, ident, why)
if got != case.get("expect"):
fails.append("%s: expected %s, got %s%s" % (name, case.get("expect"), got, (" — " + why) if why else ""))
elif got == "accept" and ident != case.get("identity"):
fails.append("%s: accepted, identity %s, the corpus states %s" % (name, ident, case.get("identity")))
elif got != "accept" and case.get("identity") is not None:
fails.append("%s: refused, and the corpus states an identity" % name)
if got in REASONS:
seen.add(got)
for r in REASONS:
if r not in seen:
fails.append("nothing in the corpus is refused %s" % r)
if not quiet:
for f in fails:
print("FAIL " + f)
return fails, outcomes
def section(name):
path = os.path.join(HERE, "..", "extensions", "sink-energy.md")
with open(path, encoding="utf-8") as f:
text = f.read()
at = text.index("\n## " + name)
end = text.find("\n## ", at + 1)
return text[at:end if end >= 0 else len(text)]
def reasons_listed():
"""§8's table, in order."""
return [line.split("`")[1] for line in section("8. Reasons").splitlines() if line.startswith("| `")]
def prose_reasons():
"""§8's prose: the row reasons and the unmetered reasons."""
body = " ".join(section("8. Reasons").split())
a = body.index("The **row reasons**")
b = body.index("The **unmetered reasons**")
return re.findall(r"`([a-z_]+)`", body[a:b]), re.findall(r"`([a-z_]+)`", body[b:])
# ---------------------------------------------------------------- the measured tables
def load_table_dir(d):
"""One measured table's three files, as bytes (None where a file is missing)."""
files = {}
for n in ("table.json", "readings.json", "procedure.txt"):
p = os.path.join(d, n)
if os.path.isfile(p):
with open(p, "rb") as f:
files[n] = f.read()
else:
files[n] = None
return files
def load_tables(corpus_dir):
out = []
root = os.path.join(corpus_dir, "tables")
if not os.path.isdir(root):
return out
for sink in sorted(os.listdir(root)):
d = os.path.join(root, sink)
if os.path.isdir(d):
out.append((sink, load_table_dir(d)))
return out
# §9 has the corpus hold the reference sinks' measured tables. While they are being taken, a
# corpus without them is a NOTE, not a failure; set this to True once they are committed.
REQUIRE_TABLES = True
def check_tables(tables, quiet=False, prefix="tables/"):
fails, lines = [], []
if not tables:
msg = "no measured table under tables/ (§9: the corpus holds the reference sinks' tables)"
if REQUIRE_TABLES:
fails.append(msg)
else:
lines.append("NOTE " + msg)
for sink, files in tables:
if any(files[n] is None for n in files):
fails.append("%s: missing %s" % (prefix + sink, ", ".join(n for n in files if files[n] is None)))
continue
try:
rec = loads(files["table.json"].decode("utf-8"))
readings = loads(files["readings.json"].decode("utf-8"))
except (ValueError, UnicodeDecodeError) as e:
fails.append("%s: does not read as JSON (%s)" % (prefix + sink, e))
continue
try:
ident = verify_table(rec, readings, files["readings.json"], True)
except Refused as e:
fails.append("%s: refused %s — %s" % (prefix + sink, e.reason, e.why))
continue
except (KeyError, TypeError, ValueError, AttributeError, IndexError) as e:
fails.append("%s: verifier error %s: %s" % (prefix + sink, type(e).__name__, e))
continue
try:
if not_jcs(readings, files["readings.json"]):
lines.append("NOTE %s: readings.json is not the JCS form of its object (§4.3)" % (prefix + sink))
except ValueError:
pass
if sha(files["procedure.txt"]).hex() != rec["procedure_sha256"]:
fails.append("%s: procedure.txt's SHA-256 is not `procedure_sha256`" % (prefix + sink))
continue
m = rec["machine"]
lines.append("%s: %s %s, %s, %d cores, %d GiB; measured %s; %d rounds at %d us; identity %s"
% (prefix + sink, m["os"], m["arch"], m["processor"], m["cores"], m["memory_gib"], rec["measured"],
rec["rounds"], rec["sample_us"], ident.hex()))
for row in rec["rows"]:
lines.append(" %-28s %-8s %-11s %-10s %-12s %s" % (
row["capability"], row["path"], row["profile"], row["status"] + ("/" + row["reason"] if row["reason"] else ""),
row["joules_micro"] if row["status"] in ("figure", "relative") else "-",
row["range"] if row["range"] is not None else "-"))
if not quiet:
for f in fails:
print("FAIL " + f)
return fails, lines
def not_jcs(obj_, raw):
return jcs(obj_) != raw
# ---------------------------------------------------------------- RFC 8032 signing, for mutations
def _mul(s, p):
return ED._double_mul(s, p, 0, ED.IDENTITY)
def keypair(seed):
"""RFC 8032 §5.1.5."""
h = hashlib.sha512(seed).digest()
a = int.from_bytes(h[:32], "little")
a &= (1 << 254) - 8
a |= 1 << 254
return (a, h[32:], ED.encode(_mul(a, ED.B)))
def sign(kp, msg):
"""RFC 8032 §5.1.6."""
a, prefix, pk = kp
r = int.from_bytes(hashlib.sha512(prefix + msg).digest(), "little") % ED.L
rr = ED.encode(_mul(r, ED.B))
k = int.from_bytes(hashlib.sha512(rr + pk + msg).digest(), "little") % ED.L
return rr + ((r + k * a) % ED.L).to_bytes(32, "little")
MUT_KEY = keypair(sha(b"sink_energy_verify: the mutation self-test's own key"))
def resign(rec, kind):
rec["signer"] = MUT_KEY[2].hex()
rec["sig"] = sign(MUT_KEY, KINDS[kind][1] + jcs(body_of(rec))).hex()
# ---------------------------------------------------------------- mutations
def rekey(case):
"""A copy of an accepted case whose records signed by the case's sink are re-signed by
MUT_KEY, with every link (table ids, `prev`, `last`) carried across, so that a defect
put in afterwards is met by the rule it breaks rather than by the signature."""
c = copy.deepcopy(case)
if c["subject"] == "table":
resign(c["record"], TABLE)
return c
main = c["record"] if c["record"] is not None else c["segments"][0]
old_signer = main["signer"]
ids = {}
for t in c.get("tables") or []:
if t["signer"] == old_signer:
old = identity(t, TABLE).hex()
resign(t, TABLE)
ids[old] = identity(t, TABLE).hex()
segs = list(c.get("segments") or []) + ([c["record"]] if c["subject"] == "segment" else [])
for s in segs:
if s["signer"] != old_signer:
continue
old = identity(s, SEGMENT).hex()
if s["table"] is not None and s["table"]["id"] in ids:
s["table"]["id"] = ids[s["table"]["id"]]
if s["prev"] in ids:
s["prev"] = ids[s["prev"]]
resign(s, SEGMENT)
ids[old] = identity(s, SEGMENT).hex()
if c["subject"] == "session":
for st in c["record"]["streams"]:
st["last"] = ids.get(st["last"], st["last"])
resign(c["record"], SESSION)
return c
def flip_hex(h, at, bit=1):
b = bytearray(bytes.fromhex(h))
b[at] ^= bit
return b.hex()
def mutations(doc, tables):
"""(name, doc, tables, case name or None, the outcome the text gives the defect or None)."""
out, notes = [], []
cases = doc.get("cases", [])
def accepted(c):
return c.get("expect") == "accept"
def find(pred, rekeyed=False):
"""The first accepted case meeting `pred` (and, if `rekeyed`, still accepted once
re-signed: the positive control)."""
for c in cases:
try:
if not accepted(c) or not pred(c):
continue
except (KeyError, TypeError, IndexError, AttributeError):
continue
if not rekeyed:
return c
r = rekey(c)
got = run_case(r, doc)
if got[0] == "accept":
return r
notes.append("the re-signed copy of %s gives %s, not accept (%s)" % (c["name"], got[0], got[2]))
return None
def put(name, case, f, want, rekeyed_case=None):
if case is None:
notes.append("no case to mutate for '%s'" % name)
return
d = copy.deepcopy(doc)
i = next(k for k, c in enumerate(d["cases"]) if c["name"] == case["name"])
if rekeyed_case is not None:
d["cases"][i] = copy.deepcopy(rekeyed_case)
w = f(d["cases"][i], d)
out.append((name, d, tables, case["name"], w if isinstance(w, str) else want))
def figure_row(c):
rows = c["record"]["rows"]
return next((k for k, r in enumerate(rows) if r["status"] == "figure"), None)
is_table = lambda c: c["subject"] == "table" # noqa: E731
# 1. a table's signature
c = find(is_table)
put("a table's signature byte", c, lambda x, d: x["record"].update(sig=flip_hex(x["record"]["sig"], 0)), "signature_invalid")
# 2. a row's figure, changed by one
r = find(lambda c: is_table(c) and figure_row(c) is not None, True)
def figure_plus(x, d):
row = x["record"]["rows"][figure_row(x)]
row["joules_micro"] += 1
resign(x["record"], TABLE)
put("a row's figure, by one", r, figure_plus, "table_row_figure", r)
# 3. a round dropped
def drop_round(x, d):
x["record"]["rows"][figure_row(x)]["rounds"].pop()
resign(x["record"], TABLE)
put("a round dropped", r, drop_round, "table_rounds_invalid", r)
# 4. two rows swapped
r4 = find(lambda c: is_table(c) and len(c["record"]["rows"]) >= 2, True)
def swap_rows(x, d):
rows = x["record"]["rows"]
rows[0], rows[1] = rows[1], rows[0]
resign(x["record"], TABLE)
put("two rows swapped", r4, swap_rows, "table_row_order", r4)
# 5. a reading's interval, the digest and signature carried across
def with_readings(c):
return is_table(c) and c.get("readings") is not None and any(r["rounds"] for r in c["record"]["rows"])
r5 = find(with_readings, True)
def interval(x, d):
k = next(k for k, row in enumerate(x["record"]["rows"]) if row["rounds"])
iv = x["readings"]["rows"][k]["rounds"][0]["busy"][0]
iv[0] = 0 if iv[0] > 0 else 10 ** 9
x["record"]["readings_sha256"] = sha(readings_bytes_of(x["readings"])).hex()
resign(x["record"], TABLE)
put("a reading's interval", r5, interval, "table_readings_mismatch", r5)
# 6. the readings changed under their digest
c6 = find(with_readings)
def readings_only(x, d):
k = next(k for k, row in enumerate(x["record"]["rows"]) if row["rounds"])
x["readings"]["rows"][k]["rounds"][0]["completions"] += 1
put("the readings, under their digest", c6, readings_only, "table_readings_mismatch")
# 7. a row's status
def status_flip(x, d):
row = x["record"]["rows"][figure_row(x)]
row["status"] = "relative"
resign(x["record"], TABLE)
put("a row's status", r, status_flip, "table_row_status", r)
# 8. a row's declaration, one below its floor
def decl_minus(x, d):
rec = x["record"]
row = rec["rows"][figure_row(x)]
o = row_outcome(row, rec["sample_us"])
row["energy_uncertainty"]["relative_ppm"] = max(o["p"], o["q"]) - 1
resign(rec, TABLE)
return ("energy_class_invalid" if row["joules_micro"] * row["energy_uncertainty"]["relative_ppm"] < FLOOR
or row["energy_uncertainty"]["relative_ppm"] < 1 else "table_row_declaration")
put("a row's declaration", r, decl_minus, None, r)
# 9. a counter's status
def counter_frozen(x, d):
rec = x["record"]
prof = rec["rows"][figure_row(x)]["profile"]
for cn in rec["counters"]:
if cn["profile"] == prof:
cn["status"] = "frozen"
resign(rec, TABLE)
put("a counter's status", r, counter_frozen, "table_row_status", r)
# 10. an extra member
put("an extra member", c, lambda x, d: x["record"].update(note="x"), "record_malformed")
# 11. a segment's signature
seg = lambda m: (lambda c: c["subject"] == "segment" and c["record"]["method"] == m) # noqa: E731
c11 = find(lambda c: c["subject"] == "segment")
put("a segment's signature byte", c11, lambda x, d: x["record"].update(sig=flip_hex(x["record"]["sig"], 63, 0x10)),
"signature_invalid")
# 12. a measured segment's figure
r12 = find(seg("measured"), True)
def seg_plus(x, d):
x["record"]["joules_micro"] += 1
resign(x["record"], SEGMENT)
put("a measured segment's figure", r12, seg_plus, "segment_figure_mismatch", r12)
# 13. a measured segment's declaration
def seg_decl(x, d):
s = x["record"]
b = s["bracket"]
mm = b["busy"]["mean_uw"] - b["idle"]["mean_uw"]
f = figure_of(mm, b["window_us"], 1, 1)
p = least_p(b["idle"]["n"], b["idle"]["sd_uw"], b["busy"]["n"], b["busy"]["sd_uw"], mm, b["window_us"], 1, 1, 0, f)
s["energy_uncertainty"]["relative_ppm"] = p - 1
resign(s, SEGMENT)
return "energy_class_invalid" if f * (p - 1) < FLOOR or p - 1 < 1 else "segment_declaration_below"
put("a measured segment's declaration", r12, seg_decl, None, r12)
# 14. a table segment's class
r14 = find(lambda c: seg("table")(c) and c["record"]["table"]["id"] in held_tables(c.get("tables")), True)
def seg_class(x, d):
s = x["record"]
s["energy_provenance"] = "Estimator" if s["energy_provenance"] == "ModelBased" else "ModelBased"
resign(s, SEGMENT)
put("a table segment's class", r14, seg_class, "segment_table_mismatch", r14)
# 15. an estimated segment's figure
r15 = find(seg("estimator"), True)
put("an estimated segment's figure", r15, seg_plus, "segment_estimator_mismatch", r15)
# 16–18. a chain
chain2 = lambda c: c["subject"] == "chain" and len(c["segments"]) >= 2 # noqa: E731
c16 = find(chain2)
def chain_swap(x, d):
s = x["segments"]
s[0], s[1] = s[1], s[0]
put("a chain's receipts swapped", c16, chain_swap, "segment_chain_broken")
def chain_drop(x, d):
s = x["segments"]
s.pop(len(s) // 2 if len(s) >= 3 else 0)
put("a chain's receipt dropped", c16, chain_drop, "segment_chain_broken")
r18 = find(chain2, True)
def chain_prev(x, d):
s = x["segments"][1]
s["prev"] = sha(b"not the receipt before it").hex()
resign(s, SEGMENT)
put("a chain's prev", r18, chain_prev, "segment_chain_broken", r18)
# 19–20. a hop's share, a hop's record
def entry(c, role):
return next((h for h in c["record"]["hops"] if h["role"] == role), None)
def hop_part(x):
"""The origin's or relay's figure entry whose live-metering record the case holds."""
return next((h for h in x["record"]["hops"] if h["role"] in (ORIGIN, RELAY) and h["source"] is not None
and h["source"]["kind"] == "live-metering-hop" and h["source"]["record"] in (x.get("hops") or [])), None)
def held_hop(c):
return c["subject"] == "session" and hop_part(c) is not None
r19 = find(held_hop, True)
def share_den(x, d):
hop_part(x)["source"]["share_den"] += 1
resign(x["record"], SESSION)
put("a hop's share", r19, share_den, "split_hop_mismatch", r19)
c20 = find(held_hop)
def hop_byte(x, d):
dg = hop_part(x)["source"]["record"]
d["hops"][dg] = flip_hex(d["hops"][dg], 86)
put("a hop record's byte", c20, hop_byte, "split_hop_mismatch")
# 21. the display's figure
r21 = find(lambda c: c["subject"] == "session" and entry(c, DISPLAY) is not None
and entry(c, DISPLAY)["energy_provenance"] is not None, True)
def display_plus(x, d):
entry(x, DISPLAY)["joules_micro"] += 1
resign(x["record"], SESSION)
put("the display's figure", r21, display_plus, "split_display_mismatch", r21)
# 22–24. a session against its segment receipts
holding = lambda c: c["subject"] == "session" and len(c.get("segments") or []) >= 1 # noqa: E731
r22 = find(holding, True)
def media_plus(x, d):
x["record"]["media_us"] += 1
resign(x["record"], SESSION)
put("a session's media_us", r22, media_plus, "session_streams_mismatch", r22)
c23 = find(holding)
put("a session's segment left out", c23, lambda x, d: x["segments"].pop(), "session_streams_mismatch")
r24 = find(lambda c: holding(c) and entry(c, SINK_DECODE) is not None
and entry(c, SINK_DECODE)["energy_provenance"] is not None, True)
def decode_plus(x, d):
entry(x, SINK_DECODE)["joules_micro"] += 1
resign(x["record"], SESSION)
put("the sink-decode entry's figure", r24, decode_plus, "split_decode_mismatch", r24)
# 24b. the display entry left out of a session that presented content
r24b = find(lambda c: c["subject"] == "session" and entry(c, DISPLAY) is not None, True)
def display_out(x, d):
x["record"]["hops"] = [h for h in x["record"]["hops"] if h["role"] != DISPLAY]
resign(x["record"], SESSION)
put("the display entry left out", r24b, display_out, "split_part_invalid", r24b)
# 25–27. the corpus's own statements
c25 = find(lambda c: is_hex(c.get("identity"), 32))
def ident(x, d):
x["identity"] = flip_hex(x["identity"], 0)
if c25 is not None:
d = copy.deepcopy(doc)
ident(next(x for x in d["cases"] if x["name"] == c25["name"]), d)
out.append(("a stated identity", d, tables, None, None))
refused = next((x for x in cases if x.get("expect") in REASONS), None)
if refused is not None:
d = copy.deepcopy(doc)
x = next(y for y in d["cases"] if y["name"] == refused["name"])
x["expect"] = next(r for r in REASONS if r != refused["expect"])
out.append(("a stated reason", d, tables, None, None))
counts = {}
for x in cases:
counts[x.get("expect")] = counts.get(x.get("expect"), 0) + 1
only = next((x for x in cases if x.get("expect") in REASONS and counts[x["expect"]] == 1), None)
if only is not None:
d = copy.deepcopy(doc)
d["cases"] = [y for y in d["cases"] if y["name"] != only["name"]]
out.append(("the only case refused %s" % only["expect"], d, tables, None, None))
else:
notes.append("no reason is refused by exactly one case (the coverage mutation needs one)")
# 28–29. the measured tables
# on the first measured table that holds, alone, so that the defect is what fails
good = next((t for t in tables if not check_tables([t], quiet=True)[0]), None)
if good is not None:
sink, files = good
t2 = [(sink, dict(files))]
t2[0][1]["readings.json"] = files["readings.json"].replace(b"]]", b"] ]", 1) if b"]]" in files["readings.json"] \
else files["readings.json"] + b"\n"
out.append(("a measured table's readings", doc, t2, None, None))
t3 = [(sink, dict(files))]
t3[0][1]["procedure.txt"] = bytes([files["procedure.txt"][0] ^ 1]) + files["procedure.txt"][1:]
out.append(("a measured table's procedure", doc, t3, None, None))
elif tables:
notes.append("no measured table holds, so the two table mutations have nothing to mutate")
return out, notes
# ---------------------------------------------------------------- the self-test
def self_test():
"""Hand cases for JCS, the integer forms, the signer and the §8 parse; a list of the
checks that fail."""
fails = []
def eq(name, got, want):
if got != want:
fails.append("%s: %r, not %r" % (name, got, want))
# RFC 8785 §3.2.3's sorting example (strings only), and escapes.
o = loads('{"\\u20ac":"Euro Sign","\\r":"Carriage Return","\\ufb33":"Hebrew Letter Dalet With Dagesh",'
'"1":"One","\\ud83d\\ude00":"Emoji: Grinning Face","\\u0080":"Control",'
'"\\u00f6":"Latin Small Letter O With Diaeresis"}')
eq("jcs sorting", jcs(o), ('{"\\r":"Carriage Return","1":"One","\u0080":"Control",'
'"ö":"Latin Small Letter O With Diaeresis","€":"Euro Sign",'
'"\U0001F600":"Emoji: Grinning Face","דּ":"Hebrew Letter Dalet With Dagesh"}').encode("utf-8"))
eq("jcs escapes", jcs({"b": [3, None, "\u000f\"\\\n\u007f
"], "a": 9007199254740991}),
b'{"a":9007199254740991,"b":[3,null,"\\u000f\\"\\\\\\n\x7f\xe2\x80\xa8"]}')
for bad in (True, 1.0, -1, 2 ** 53, "\ud800"):
try:
jcs([bad])
fails.append("jcs takes %r" % (bad,))
except ValueError:
pass
x = loads('{"a":1,"a":2,"b":1.0,"c":-0,"d":1e3}')
eq("reader dup", x.dup, True)
eq("reader numbers", [type(x[k]).__name__ for k in "bcd"], ["JNum"] * 3)
eq("reader dup kept by copy", copy.deepcopy(x).dup, True)
# §4.3: powers, mean half up, sd rounded up, liveness.
eq("p half up", summary_of([[1, 2000], [1, 2000]])["mean_uw"], 1)
eq("p 1 mW", (2000 * 200000 + 200000) // (2 * 200000), 1000)
s = summary_of([[2, 2000], [4, 2000], [6, 2000], [8, 2000]]) # p = 1, 2, 3, 4
eq("summary 1..4", s, {"n": 4, "mean_uw": 3, "sd_uw": 2, "live_intervals": 4, "longest_live_run": 4})
# p = 500, 500, 0, 500, 500, 500: n·Σp² − (Σp)² = 1 250 000 over n(n − 1) = 30 is
# 41 666.7, whose root 204.1 rounds up to 205.
s = summary_of([[5, 10], [5, 10], [0, 10], [5, 10], [5, 10], [5, 10]])
eq("liveness", (s["live_intervals"], s["longest_live_run"], s["sd_uw"]), (5, 3, 205))
eq("sd one interval", summary_of([[7, 3]])["sd_uw"], 0)
eq("least_sq", [least_sq(12, 0), least_sq(12, 12), least_sq(12, 13), least_sq(0, 1), least_sq(1, 10 ** 30)],
[0, 1, 2, None, 10 ** 15])
# energy-measurement §6.2 from rest, against its real-valued §2.3 form.
m, t, c, n = 500000, 2000000, 100, 4
wn = 2 * c + n
f = figure_of(m, t, wn, 2)
eq("F from rest", f, 9804)
p = least_p(10, 10000, 10, 20000, m, t, wn, 2, n, f)
e = m * t * 2 / (1e6 * wn)
u_meas = math.sqrt((math.sqrt(10000 ** 2 / 10 + 20000 ** 2 / 10) / m) ** 2 + (n / (math.sqrt(3) * wn)) ** 2)
u_rel = math.sqrt((e * u_meas) ** 2 + 1 / 12) / f
if not 0 <= p - u_rel * 1e6 < 1.001:
fails.append("p from rest: %d against %.3f" % (p, u_rel * 1e6))
if f * p < FLOOR:
fails.append("p from rest below the floor")
# bounded (§5.2): Wn = Wd = 1, N = 0.
f = figure_of(1000, 1000000, 1, 1)
eq("F bounded", f, 1000)
p = least_p(10, 100, 20, 200, 1000, 1000000, 1, 1, 0, f)
u = math.sqrt((1e6 * math.sqrt(100 ** 2 / 10 + 200 ** 2 / 20) / 1e6) ** 2 + 1 / 12) / f
if not 0 <= p - u * 1e6 < 1.001:
fails.append("p bounded: %d against %.3f" % (p, u * 1e6))
eq("F rounds half up", figure_of(1, 500000, 1, 1), 1)
eq("F rounds down", figure_of(1, 499999, 1, 1), 0)
# the estimators and the shares.
eq("estimator-cpu-time/1", estimate_cpu(1000000, 1500), 1500000)
eq("estimator-cpu-time/1 half up", [estimate_cpu(1, 500), estimate_cpu(1, 499)], [1, 0])
eq("estimator-display/1", estimate_display(30000, 125, 1000000, 250), 15000000)
eq("estimator-display/1 nits 0", estimate_display(30000, 0, 1000000, 250), 0)
eq("shares", [share_of(1000, 1, 3), share_of(1000, 2, 3), share_of(1, 1, 2), share_of(1, 1, 3)], [333, 667, 1, 0])
eq("table formula", [table_figure(1000, 3, 2), table_figure(1, 1, 2), table_figure(1, 1, 3)], [1500, 1, 0])
eq("q", least_sq(12 * 1000 * 1000, 10 ** 12 * 10 ** 2), 2887)
eq("ceil", ceil_div(7, 2), 4)
# the median by (F, r)
figs = sorted([(5, 0), (3, 1), (5, 2), (3, 3), (4, 4), (9, 5), (1, 6)])
eq("median", figs[len(figs) // 2], (4, 4))
eq("decoder", [decoder_ok(v) for v in ("builtin:[email protected]", "builtin:wai@v1", "platform:videotoolbox",
"platform:Video", "builtin:a@1+b.c-d")], [True, False, True, False, True])
eq("dates", [date_ok(v) for v in ("2026-02-29", "2028-02-29", "2026-13-01", "2026-10-22", "26-10-22")],
[False, True, False, True, False])
# RFC 8032 §7.1 TEST 1 through the mutation signer.
kp = keypair(bytes.fromhex("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"))
eq("signer public key", kp[2].hex(), "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a")
eq("signer TEST 1", sign(kp, b"").hex(), "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155"
"5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b")
eq("signer verifies", ED.verify(MUT_KEY[2], b"m", sign(MUT_KEY, b"m")), None)
eq("§8 row reasons", tuple(prose_reasons()[0]), ROW_REASONS)
eq("§8 unmetered reasons", tuple(prose_reasons()[1]), UNMETERED_REASONS)
return fails
def main(argv):
fail = 0
st = self_test()
for f in st:
print("FAIL self-test " + f)
print("%s the self-test: RFC 8785, the reader, the integer forms, the estimators, RFC 8032 signing" % ("PASS" if not st else "FAIL"))
fail += bool(st)
listed = reasons_listed()
ok = listed == REASONS
print("%s §8 lists exactly the reasons this verifier raises%s" % ("PASS" if ok else "FAIL", "" if ok else ": %r" % listed))
fail += not ok
if argv == ["--self-test"]:
return 1 if fail else 0
if argv[0] == "--table":
d = argv[1]
if not os.path.isdir(d):
print("FAIL %s is not a directory" % d)
return 1
tfails, lines = check_tables([(d, load_table_dir(d))], prefix="")
for line in lines:
print(line)
print("%s the measured table in %s is accepted with its readings and procedure" % ("PASS" if not tfails else "FAIL", d))
return 1 if fail or tfails else 0
corpus_dir = argv[0]
path = os.path.join(corpus_dir, "vectors.json")
tables = load_tables(corpus_dir)
if not os.path.exists(path):
print("FAIL %s does not exist" % path)
return 1
with open(path, encoding="utf-8") as f:
doc = loads(f.read())
notes = []
fails, outs = check(doc, notes=notes)
for n in notes:
print("NOTE " + n)
n_acc = sum(1 for o in outs.values() if o[0] == "accept")
print("%s %d cases verify from the text (%d accepted, %d refused)"
% ("PASS" if not fails else "FAIL", len(doc.get("cases", [])), n_acc, len(outs) - n_acc))
fail += bool(fails)
tfails, lines = check_tables(tables)
for line in lines:
print(line)
n_bad = sum(1 for t in tables if check_tables([t], quiet=True)[0])
print("%s %d of %d measured tables accepted with their readings and procedures"
% ("PASS" if not tfails else "FAIL", len(tables) - n_bad, len(tables)))
fail += bool(tfails)
muts, notes = mutations(doc, tables)
for n in notes:
print("NOTE " + n)
caught = 0
for name, d, tb, case, want in muts:
f1, outs = check(d, quiet=True)
f2, _ = check_tables(tb, quiet=True) if tb is not tables else ([], [])
got = outs.get(case, (None,))[0] if case is not None else None
if not (f1 or f2):
print("FAIL the mutation '%s' goes unnoticed" % name)
fail += 1
elif want is not None and got != want:
print("FAIL the mutation '%s' of %s gives %s, the text gives %s (%s)" % (name, case, got, want, outs[case][2]))
fail += 1
else:
caught += 1
kinds_ok = len(muts) >= 12
print("%s %d of %d mutated copies of the corpus fail%s" % ("PASS" if caught == len(muts) and kinds_ok else "FAIL", caught,
len(muts), "" if kinds_ok else " (fewer than 12 kinds)"))
fail += not kinds_ok
return 1 if fail else 0
if __name__ == "__main__":
args = sys.argv[1:]
if not (len(args) == 1 and args[0] != "--table" or len(args) == 2 and args[0] == "--table"):
print("usage: sink_energy_verify.py <live-conformance/sink-energy> | --table <dir> | --self-test", file=sys.stderr)
sys.exit(2)
sys.exit(main(sys.argv[1:]))