open-standards/wai/oer-conformance/generate_edge_vectors.py
Transaction Science ac387a1db5
Some checks failed
no-vanity-metrics / Scan committed Markdown for vanity metrics (push) Successful in 4s
standards workspaces build + test / jouleclaw-rs (push) Successful in 1m50s
standards workspaces build + test / eoc-rs (push) Successful in 1m54s
standards workspaces build + test / arl-rs (push) Successful in 2m10s
standards workspaces build + test / aac-rs (push) Successful in 40s
standards workspaces build + test / joule-code-rs (push) Successful in 38s
standards workspaces build + test / jcp-rs (push) Successful in 1m18s
standards workspaces build + test / joulecontract-rs (push) Successful in 30s
standards workspaces build + test / map-rs (push) Successful in 30s
standards workspaces build + test / proof-rs (push) Successful in 1m11s
standards workspaces build + test / mesh-rs (push) Successful in 26s
standards workspaces build + test / joule-ui-rs (push) Successful in 2m32s
standards workspaces build + test / openpay (push) Successful in 1m21s
standards workspaces build + test / sandbox-rs (push) Successful in 2m12s
WAI conformance / cargo-class corpora · linux-arm64 (push) Successful in 51s
WAI conformance / cross-arch byte-equality · linux-arm64 (push) Successful in 18s
standards workspaces build + test / jouledesk-rs (push) Successful in 2m39s
standards workspaces build + test / smart-byte-rs (push) Successful in 2m30s
WAI conformance / cargo-class corpora · linux (push) Successful in 1m11s
WAI conformance / cross-arch byte-equality · linux (push) Successful in 15s
standards workspaces build + test / joulehook-rs (push) Successful in 3m48s
WAI conformance / C2PA manifest emission · signed, read back, validated (push) Successful in 40s
standards workspaces build + test / sense-rs (push) Successful in 2m22s
standards workspaces build + test / macOS energy backend (jcp-energy) (push) Successful in 2m32s
WAI conformance / cargo-class corpora · macos (push) Successful in 55s
WAI conformance / cross-arch byte-equality · macos (push) Successful in 14s
WAI conformance / cargo-class corpora · windows (push) Has been cancelled
WAI conformance / cross-arch byte-equality · windows (push) Has been cancelled
wai/oer: settle draft 0.1's open points; make the two verifiers agree on every input
Departures from OER/2 draft 0.1, each in extensions/oer-receipts.md §9:
- decisions are named oer.decision.*, not wai.settle.* (WAI's namespace is for payload formats)
- the stage list behind bundle.provenance_root is serialised exactly as the body is,
  pinned by a non-ASCII fixture
- the number profile is normative: I-JSON integers, decimal strings in JSON's number
  grammar (<=34 digits), anything else malformed
- a document outside the document profile is refused whole: a number whose nearest
  binary64 is infinite, NaN/Infinity, an unpaired surrogate, a repeated member name,
  nesting past 64
- every composition check is exact (num-bigint / exact decimal context), ln 2 pinned
  as a decimal, every tolerance scaled by the figure's magnitude
- the order of the reasons reported alone, and every member judged on its value, are
  stated, so each mistyped member has one named reason
- published Ed25519 keys are decoded strictly: canonical encoding, not small order
- abstention is its own outcome (abstain, no answer, no record), held by a new reason,
  abstention_settled; escalate is a verdict returned from upstream

Four rounds of adversarial review with differential fuzzing drove this; the last fuzz
found one remaining divergence (repeated member names), now refused by both. The
edge corpus grows to 99 hand-declared vectors plus unreadable/ (11 documents every
verifier must refuse); each rule was falsified in both verifiers. serde_json gains
float_roundtrip under the oer feature so Rust rounds as Python does.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 09:15:31 -04:00

868 lines
38 KiB
Python

#!/usr/bin/env python3
"""Edge vectors for OER/2 as extensions/oer-receipts.md profiles draft 0.1: every
behaviour the upstream nine never exercise.
The nine published vectors cover eight reason names. This file adds one vector per
remaining behaviour a verifier must get right -- each reason, each number shape and
decimal-string defect, each bound and tolerance edge, the order of the reasons
reported alone, and abstention. Each carries at most ONE defect. Where the edit
leaves the seal intact it is re-sealed (fresh receipt id, receipt hash and Ed25519
signature, using the published test seed from generate_vectors.py), so the declared
reason is the only one it can honestly produce; a vector whose reason is reported
alone before any hash is checked is left unsealed.
Every `expected` below is written by hand from the rules in
extensions/oer-receipts.md. None is copied from a verifier's output: a vector whose
expectation came from the code under test would only prove the code agrees with
itself.
Run: python3 generate_edge_vectors.py (writes edge_vectors.json beside it)
"""
import copy, hashlib, json, os, sys
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import oer2_verify as V # canonical form + hashing only; the fixture pins those independently
from cryptography.hazmat.primitives.asymmetric import ed25519
SEED = hashlib.sha256(b"settlement world node ledger vector key").digest()
PRIV = ed25519.Ed25519PrivateKey.from_private_bytes(SEED)
base = json.load(open(os.path.join(HERE, "vectors.json")))
KEYS = base["keys"]
v01 = next(v for v in base["vectors"] if v["name"].startswith("v01"))
v03 = next(v for v in base["vectors"] if v["name"].startswith("v03"))
R = v01["receipts"][0] # a valid, signed decision receipt
BUNDLE = next(r for r in v03["receipts"] if r.get("kind") == "bundle")
def reseal(r):
"""Recompute id, chained hash and signature so the receipt is otherwise valid."""
body = V.canonical_bytes(r)
r["receipt_id"] = V.h(r["hash_alg"], body)
r["chain"]["receipt_hash"] = V.h(r["hash_alg"], r["chain"]["prev_hash"].encode() + body)
r["chain"]["signature"] = PRIV.sign(r["chain"]["receipt_hash"].encode()).hex()
return r
def edit(src, fn, seal=True):
r = copy.deepcopy(src)
fn(r)
return reseal(r) if seal else r
def stage_root(stages, alg):
return V.h(alg, V.stage_list_bytes(stages))
vectors = []
# A hash algorithm the verifier lacks is a capability gap, spelled exactly
# `missing_capability` -- the reference once reported "'missing_capability" here.
vectors.append({"name": "e01 unsupported hash algorithm",
"receipts": [edit(R, lambda r: r.update(hash_alg="sha3-512"), seal=False)],
"expected": ["missing_capability"]})
vectors.append({"name": "e02 unsupported signature algorithm",
"receipts": [edit(R, lambda r: r.update(sig_alg="ecdsa-p256"))],
"expected": ["missing_capability"]})
# A receipt too broken to check is reported, not raised.
vectors.append({"name": "e03 energy member absent",
"receipts": [edit(R, lambda r: r.pop("energy"))],
"expected": ["malformed"]})
vectors.append({"name": "e04 grade outside the vocabulary",
"receipts": [edit(R, lambda r: r["provenance"].update(how="guessed"))],
"expected": ["grade_unknown"]})
vectors.append({"name": "e05 kind outside the vocabulary",
"receipts": [edit(R, lambda r: r.update(kind="teleport"))],
"expected": ["unknown_kind"]})
vectors.append({"name": "e06 measurement boundary not stated",
"receipts": [edit(R, lambda r: r["energy"].update(boundary=""))],
"expected": ["boundary_missing"]})
vectors.append({"name": "e07 Landauer floor misstated",
"receipts": [edit(R, lambda r: r["floor"].update(floor_j="1"))],
"expected": ["floor_mismatch"]})
vectors.append({"name": "e08 signer not in the key set",
"receipts": [edit(R, lambda r: r["chain"].update(signer="ed25519:nobody"), seal=False)],
"expected": ["signer_unknown"]})
# A receipt id that recurs must not hide the reasons of the earlier receipt with that id.
def repeated_id():
a = edit(R, lambda r: r["provenance"].update(how="guessed")) # grade_unknown
b = copy.deepcopy(R)
b["energy"]["boundary"] = ""
b["chain"]["prev_hash"] = a["chain"]["receipt_hash"] # chains onto a
b = reseal(b) # boundary_missing
b["receipt_id"] = a["receipt_id"] # + receipt_id_mismatch
return [a, b]
vectors.append({"name": "e09 a repeated receipt id hides nothing",
"receipts": repeated_id(),
"expected": ["boundary_missing", "grade_unknown", "receipt_id_mismatch"]})
def bundle_sum():
def f(r):
r["bundle"]["stages"][0]["joules"] = "99999"
r["bundle"]["provenance_root"] = stage_root(r["bundle"]["stages"], r["hash_alg"])
return edit(BUNDLE, f)
vectors.append({"name": "e10 bundle stages do not sum to the total",
"receipts": [bundle_sum()],
"expected": ["bundle_sum_mismatch"]})
vectors.append({"name": "e11 bundle without its efficiency",
"receipts": [edit(BUNDLE, lambda r: r.pop("efficiency"))],
"expected": ["efficiency_missing"]})
# A record store or ledger too broken to check fails its check rather than crashing.
def broken_record():
v = copy.deepcopy(v01)
served = next(r for r in v["receipts"]
if (r.get("settlement") or {}).get("served_from_record"))
del v["records"][served["settlement"]["record_id"]]["created"]
return v
e12 = broken_record()
vectors.append({"name": "e12 a cited record cannot be rehashed",
"receipts": e12["receipts"], "records": e12["records"],
"expected": ["record_mismatch"]})
e13 = copy.deepcopy(v01)
del e13["ledger"]["meter_joules"]
vectors.append({"name": "e13 ledger without a meter figure",
"receipts": e13["receipts"], "ledger": e13["ledger"],
"expected": ["ledger_mismatch"]})
# Literals json.dump cannot write (-0, an exponent on an integer, a float that
# parsers round differently) go in as sentinels and are swapped in after
# serialisation, each exactly once.
LITERALS = {}
def lit(text):
key = "__oer_literal_%d__" % len(LITERALS)
LITERALS[key] = text
return key
def resealed_over(value, literal, path=("settlement", "reuse_count")):
"""Seal R with `value` at `path` -- what a parser that reads `literal` leniently
would hash -- then write `literal` there instead."""
r = edit(R, lambda r: r[path[0]].update({path[1]: value}))
r[path[0]][path[1]] = lit(literal)
return r
def with_number(n):
return edit(R, lambda r: r["settlement"].update(reuse_count=n))
# The number profile (extension section 4): a receipt body carries integers within
# I-JSON's +-(2**53 - 1) and decimal strings, nothing else. Each forbidden shape is
# read differently by different JSON parsers, so it is reported as malformed rather
# than hashed two ways -- and the bounds themselves are pinned from both sides.
vectors.append({"name": "e14 a figure written as a JSON float",
"receipts": [edit(R, lambda r: r["work"].update(latency_s=0.0017))],
"expected": ["malformed"]})
vectors.append({"name": "e15 an integer wider than 64 bits",
"receipts": [with_number(2**64)],
"expected": ["malformed"]})
# A parser that reads -0 as the integer zero finds this valid; one that reads it as
# a float (serde_json) computes a different receipt id. Neither is the declared reason.
vectors.append({"name": "e16 negative zero",
"receipts": [resealed_over(0, "-0")],
"expected": ["malformed"]})
vectors.append({"name": "e17 an integer at the upper bound",
"receipts": [with_number(2**53 - 1)], "expected": []})
vectors.append({"name": "e18 an integer at the lower bound",
"receipts": [with_number(-(2**53 - 1))], "expected": []})
vectors.append({"name": "e19 an integer one past the upper bound",
"receipts": [with_number(2**53)], "expected": ["malformed"]})
vectors.append({"name": "e20 an integer one past the lower bound",
"receipts": [with_number(-(2**53))], "expected": ["malformed"]})
vectors.append({"name": "e21 an integer written with an exponent",
"receipts": [resealed_over(100, "1e2")], "expected": ["malformed"]})
vectors.append({"name": "e22 a float inside an array",
"receipts": [edit(R, lambda r: r["subject"]["inputs"].append(0.5))],
"expected": ["malformed"]})
# Of the reasons reported alone, unknown_major comes first, then canonical_failure,
# then malformed (section 7). Unsealed: the one reason reported is all there is.
vectors.append({"name": "e23 a member not listed for its path",
"receipts": [edit(R, lambda r: r.update(extra="x"), seal=False)],
"expected": ["canonical_failure"]})
vectors.append({"name": "e24 canonical_failure comes before a forbidden number",
"receipts": [edit(R, lambda r: (r.update(extra="x"), r["work"].update(latency_s=0.5)),
seal=False)],
"expected": ["canonical_failure"]})
def float_oer():
r = copy.deepcopy(R)
r["oer"] = lit("2.99999999999999977") # 3.0 to one parser, 2.9999999999999996 to another
return r
vectors.append({"name": "e25 a version written as a number",
"receipts": [float_oer()], "expected": ["unknown_major"]})
vectors.append({"name": "e26 unknown_major comes before a forbidden number",
"receipts": [edit(R, lambda r: (r.update(oer="3.0"), r["work"].update(latency_s=0.5)),
seal=False)],
"expected": ["unknown_major"]})
vectors.append({"name": "e27 kind absent",
"receipts": [edit(R, lambda r: r.pop("kind"))], "expected": ["unknown_kind"]})
# A decimal string is JSON's number grammar, in ASCII, at most 34 significand digits
# with a one-to-three-digit exponent. Each variant below means the same number to a
# lenient decimal parser -- so a verifier without the grammar finds a valid receipt --
# and is not a decimal string.
def respelled(fn):
def f(r):
old = r["energy"]["breakdown"]["compute_j"]
new = fn(old)
assert new != old and Decimal(new) == Decimal(old), (old, new) # same number, leniently
r["energy"]["breakdown"]["compute_j"] = new
return edit(R, f)
def arabic_indic(s):
i = next(i for i, c in enumerate(s) if c.isdigit())
return s[:i] + chr(0x660 + int(s[i])) + s[i + 1:]
def widened(s):
mant, _, exp = s.partition("e")
mant = mant if "." in mant else mant + "."
digits = sum(c.isdigit() for c in mant)
return mant + "0" * (35 - digits) + ("e" + exp if exp else "")
def four_digit_exponent(s):
mant, _, exp = s.partition("e")
if not exp:
return mant + "e0000"
sign, digits = (exp[0], exp[1:]) if exp[0] in "+-" else ("", exp)
return mant + "e" + sign + digits.zfill(4)
from decimal import Decimal
for name, fn in [("e28 a decimal string with a leading plus", lambda s: "+" + s),
("e29 a decimal string with surrounding space", lambda s: " " + s + " "),
("e30 a decimal string with a non-ASCII digit", arabic_indic),
("e31 a decimal string with 35 significand digits", widened),
("e32 a decimal string with a four-digit exponent", four_digit_exponent)]:
vectors.append({"name": name, "receipts": [respelled(fn)], "expected": ["malformed"]})
# An abstention makes no verdict claim: no answer, and no record anything could later
# be served from (section 3). The first is the valid shape; each of the others adds
# exactly one claim an abstention cannot make.
def abstain(r):
r["intent"] = "create"
r["subject"]["output"] = ""
r["work"]["outcome"] = "abstain"
r["settlement"].update(served_from_record=False, record_id="", record_hash="", reuse_count=0)
vectors.append({"name": "e33 an abstention",
"receipts": [edit(R, abstain)], "expected": []})
vectors.append({"name": "e34 an abstention that carries an answer",
"receipts": [edit(R, lambda r: (abstain(r), r["subject"].update(output="authorize")))],
"expected": ["abstention_settled"]})
vectors.append({"name": "e35 an abstention that names a record",
"receipts": [edit(R, lambda r: (abstain(r), r["settlement"].update(
record_id=R["settlement"]["record_id"])))],
"expected": ["abstention_settled"]})
e36 = copy.deepcopy(v01)
e36["ledger"]["meter_joules"] = "+" + e36["ledger"]["meter_joules"]
vectors.append({"name": "e36 a ledger figure that is not a decimal string",
"receipts": e36["receipts"], "ledger": e36["ledger"],
"expected": ["ledger_mismatch"]})
vectors.append({"name": "e37 a receipt that is not an object",
"receipts": ["not a receipt"], "expected": ["malformed"]})
# Every composition check is exact (section 6). The breakdown sums to 0.5 + 1e-33
# against a total of 0.499999999: off by 1e-9 + 1e-33, which exceeds the tolerance
# of 1e-9 by 1e-33. Rounded to 28 digits the sum is 0.5, the difference exactly 1e-9,
# and the receipt passes -- the check has been decided by rounding noise.
def past_28_digits(r):
b = r["energy"]["breakdown"]
for k in b:
b[k] = "0"
b["compute_j"], b["movement_j"] = "0.5", "1e-33"
r["energy"]["joules_total"] = "0.499999999"
vectors.append({"name": "e38 a sum that misses its tolerance only past 28 digits",
"receipts": [edit(R, past_28_digits)], "expected": ["sum_mismatch"]})
# ...and one exactly at it: off by 1e-9 against a tolerance of 1e-9 is within it.
def at_tolerance(r):
b = r["energy"]["breakdown"]
for k in b:
b[k] = "0"
b["compute_j"] = "0.5"
r["energy"]["joules_total"] = "0.499999999"
vectors.append({"name": "e39 a sum exactly at its tolerance",
"receipts": [edit(R, at_tolerance)], "expected": []})
# The Landauer floor is held to 1% (section 6), exactly: ln 2 is the decimal
# 0.6931471805599453. A floor 0.9% off passes and one 2% off does not, so a verifier
# with a tolerance outside that band fails one of the pair.
def floor_off(factor):
def f(r):
with V.localcontext(V.EXACT):
floor = (V.dec(r["floor"]["bits_committed"]) * V.KBOLTZ
* V.dec(r["energy"]["temperature_k"]) * V.LN2)
r["floor"]["floor_j"] = "%.15e" % (floor * Decimal(factor))
return f
vectors.append({"name": "e40 a floor 0.9% off",
"receipts": [edit(R, floor_off("1.009"))], "expected": []})
vectors.append({"name": "e41 a floor 2% off",
"receipts": [edit(R, floor_off("1.02"))], "expected": ["floor_mismatch"]})
# Every tolerance, exactly at its edge and just past it, on both sides (section 6:
# "within t" is |a - b| <= t, and t scales by the figure's magnitude). Each written
# figure is checked to be a decimal string the grammar accepts, so the only thing a
# vector can be judged on is where the verifier draws the edge.
def exact(fn):
with V.localcontext(V.EXACT):
return fn()
def decimal_string(d):
# normalize() rounds to the context's precision, so it runs in the exact one: in
# the default 28-digit context it would silently drop a nudge in the 34th digit.
s = format(exact(d.normalize), "E") if d != 0 else "0"
assert Decimal(s) == d, (s, d)
V.dec(s) # raises if the grammar (at most 34 digits) would refuse it
return s
def only_compute(r, compute, total):
b = r["energy"]["breakdown"]
for k in b:
b[k] = "0"
b["compute_j"] = compute
r["energy"]["joules_total"] = total
vectors.append({"name": "e42 a sum past its tolerance on the other side",
"receipts": [edit(R, lambda r: only_compute(r, "0.5", "0.500000001000000000000000000000001"))],
"expected": ["sum_mismatch"]})
# -5 against -4.999999997 is off by 3e-9, within 1e-9 x |-5|; a verifier that scales
# by the signed figure (max(1, -5) = 1) rejects it.
vectors.append({"name": "e43 a negative sum within its tolerance",
"receipts": [edit(R, lambda r: only_compute(r, "-5", "-4.999999997"))], "expected": []})
def floor_at(factor, nudge="0"):
def f(r):
floor = exact(lambda: V.dec(r["floor"]["bits_committed"]) * V.KBOLTZ
* V.dec(r["energy"]["temperature_k"]) * V.LN2)
r["floor"]["floor_j"] = decimal_string(exact(lambda: floor * Decimal(factor) + Decimal(nudge)))
return f
vectors.append({"name": "e44 a floor exactly 1% high",
"receipts": [edit(R, floor_at("1.01"))], "expected": []})
vectors.append({"name": "e45 a floor 1% high and one unit in the 34th digit",
"receipts": [edit(R, floor_at("1.01", "1e-51"))], "expected": ["floor_mismatch"]})
vectors.append({"name": "e46 a floor exactly 1% low",
"receipts": [edit(R, floor_at("0.99"))], "expected": []})
vectors.append({"name": "e47 a floor 2% low",
"receipts": [edit(R, floor_at("0.98"))], "expected": ["floor_mismatch"]})
def stage_sum(r):
return exact(lambda: sum(V.dec(s["joules"]) for s in r["bundle"]["stages"]))
def bundle_total(offset):
"""A bundle whose total sits `offset(st)` from its stage sum; the breakdown moves
with the total, so the bundle sum is the only check that can object."""
def f(r):
st = stage_sum(r)
total = decimal_string(exact(lambda: st + offset(st)))
only_compute(r, total, total)
return f
vectors.append({"name": "e48 a bundle exactly at its tolerance",
"receipts": [edit(BUNDLE, bundle_total(lambda st: -st * Decimal("1e-9")))], "expected": []})
vectors.append({"name": "e49 a bundle just past its tolerance",
"receipts": [edit(BUNDLE, bundle_total(lambda st: -st * Decimal("1e-9") - Decimal("1e-30")))],
"expected": ["bundle_sum_mismatch"]})
def negative_bundle(r):
st = stage_sum(r)
first = r["bundle"]["stages"][0]
first["joules"] = decimal_string(exact(lambda: V.dec(first["joules"]) - st - 5)) # stages now sum to -5
r["bundle"]["provenance_root"] = stage_root(r["bundle"]["stages"], r["hash_alg"])
only_compute(r, "-4.999999997", "-4.999999997")
vectors.append({"name": "e50 a negative bundle within its tolerance",
"receipts": [edit(BUNDLE, negative_bundle)], "expected": []})
def ledger_with(unallocated_for):
"""v01's receipts with `unallocated_joules` set so the identity lands where asked."""
v = copy.deepcopy(v01)
L = v["ledger"]
rest = exact(lambda: sum(V.dec(r["energy"]["joules_total"]) for r in v["receipts"])
+ V.dec(L["carried_forward_joules"]))
L["unallocated_joules"] = decimal_string(exact(lambda: unallocated_for(rest, V.dec(L["meter_joules"]))))
return v
def ledger_vector(name, v, expected):
vectors.append({"name": name, "receipts": v["receipts"], "ledger": v["ledger"], "expected": expected})
ledger_vector("e51 a ledger exactly at its tolerance",
ledger_with(lambda rest, m: m - m * Decimal("1e-9") - rest), [])
ledger_vector("e52 a ledger just past its tolerance on the other side",
ledger_with(lambda rest, m: m + m * Decimal("1e-9") + Decimal("1e-25") - rest), ["ledger_mismatch"])
def negative_ledger():
v = ledger_with(lambda rest, m: Decimal(-5) - rest) # everything now sums to -5
v["ledger"]["meter_joules"] = "-4.999999997"
return v
ledger_vector("e53 a negative ledger within its tolerance", negative_ledger(), [])
vectors.append({"name": "e54 an abstention that cites a record hash",
"receipts": [edit(R, lambda r: (abstain(r), r["settlement"].update(
record_hash=R["settlement"]["record_hash"])))],
"expected": ["abstention_settled"]})
vectors.append({"name": "e55 an abstention served from a record",
"receipts": [edit(R, lambda r: (abstain(r), r["settlement"].update(served_from_record=True)))],
"expected": ["abstention_settled"]})
# The decimal-string limits from the accepting side: exactly 34 digits, and a one-
# and a three-digit exponent, are all decimal strings. Every digit before the
# exponent counts toward the 34, leading zeros included.
def one_digit_exponent(s):
mant, _, exp = s.partition("e")
return mant + "e" + ("-" if exp.startswith("-") else "") + exp.lstrip("+-").lstrip("0")
def three_digit_exponent(s):
mant, _, exp = s.partition("e")
sign, digits = (exp[0], exp[1:]) if exp[0] in "+-" else ("", exp)
return mant + "e" + sign + digits.zfill(3)
def digits_34(s):
mant, _, exp = s.partition("e")
mant = mant if "." in mant else mant + "."
return mant + "0" * (34 - sum(c.isdigit() for c in mant)) + ("e" + exp if exp else "")
for name, fn in [("e56 a decimal string with exactly 34 significand digits", digits_34),
("e57 a decimal string with a one-digit exponent", one_digit_exponent),
("e58 a decimal string with a three-digit exponent", three_digit_exponent)]:
vectors.append({"name": name, "receipts": [respelled(fn)], "expected": []})
def leading_zeros(s):
plain = format(Decimal(s), "f") # 0.00000169412 for 1.694120e-06
return plain + "0" * (35 - sum(c.isdigit() for c in plain))
vectors.append({"name": "e59 leading zeros count toward the 34 digits",
"receipts": [respelled(leading_zeros)], "expected": ["malformed"]})
# --- the rest of each tolerance: its base, its other side, and exactness past 34 digits
# 10 against 9.99999999 is off by 1e-8, exactly 1e-9 x |sum|: within. Scaled by the
# total instead (1e-9 x 9.99999999) it would not be -- the base is the sum (section 6).
vectors.append({"name": "e60 a sum exactly at its tolerance, scaled by the sum",
"receipts": [edit(R, lambda r: only_compute(r, "10", "9.99999999"))], "expected": []})
# 0.5 + 1e-60 against 0.499999999 misses by 1e-60; rounded to 34 digits (decimal128)
# the sum is 0.5 and the miss vanishes.
vectors.append({"name": "e61 a sum that misses its tolerance only past 34 digits",
"receipts": [edit(R, lambda r: (only_compute(r, "0.5", "0.499999999"),
r["energy"]["breakdown"].update(movement_j="1e-60")))],
"expected": ["sum_mismatch"]})
vectors.append({"name": "e62 a bundle just past its tolerance on the other side",
"receipts": [edit(BUNDLE, bundle_total(lambda st: st * Decimal("1e-9") + Decimal("1e-30")))],
"expected": ["bundle_sum_mismatch"]})
def small_bundle(r):
st = stage_sum(r)
first = r["bundle"]["stages"][0]
first["joules"] = decimal_string(exact(lambda: V.dec(first["joules"]) - st + Decimal("0.5")))
r["bundle"]["provenance_root"] = stage_root(r["bundle"]["stages"], r["hash_alg"])
only_compute(r, "0.499999999", "0.499999999")
# Stages summing to 0.5 against 0.499999999: off by 1e-9, within 1e-9 x max(1, 0.5).
vectors.append({"name": "e63 a small bundle exactly at its tolerance",
"receipts": [edit(BUNDLE, small_bundle)], "expected": []})
ledger_vector("e64 a ledger just past its tolerance on the low side",
ledger_with(lambda rest, m: m - m * Decimal("1e-9") - Decimal("1e-25") - rest), ["ledger_mismatch"])
def small_ledger():
v = ledger_with(lambda rest, m: Decimal("0.499999999") - rest)
v["ledger"]["meter_joules"] = "0.5"
return v
ledger_vector("e65 a small ledger exactly at its tolerance", small_ledger(), [])
# A negative temperature makes the floor negative; 1% of its magnitude is still the
# tolerance, so a floor_j 1% further from zero is within it.
def negative_floor(r):
r["energy"]["temperature_k"] = "-3.000000e+02"
floor_at("1.01")(r)
vectors.append({"name": "e66 a negative floor exactly 1% off",
"receipts": [edit(R, negative_floor)], "expected": []})
# --- members and shapes: each is reported the same way by every verifier (sections 3, 7)
vectors.append({"name": "e67 a member not listed for chain",
"receipts": [edit(R, lambda r: r["chain"].update(extra="x"), seal=False)],
"expected": ["canonical_failure"]})
vectors.append({"name": "e68 a member not listed for chain.anchor",
"receipts": [edit(R, lambda r: r["chain"].update(
anchor={"path": "iridium", "delivered_at": 1, "root": "sha256:00", "extra": "x"}), seal=False)],
"expected": ["canonical_failure"]})
# The first receipt's own hash is not a string: its hash and signature fail, and
# the second links to nothing, however its prev_hash reads.
def unlinked():
a = copy.deepcopy(R)
b = edit(R, lambda r: None)
b["chain"]["prev_hash"] = a["chain"]["receipt_hash"]
b = reseal(b)
a["chain"]["receipt_hash"] = 5
return [a, b]
vectors.append({"name": "e69 a chain link to a hash that is not a string",
"receipts": unlinked(),
"expected": ["chain_break", "receipt_hash_mismatch", "signature_invalid"]})
vectors.append({"name": "e70 a kind that is not a string",
"receipts": [edit(R, lambda r: r.update(kind=["decision"]))], "expected": ["unknown_kind"]})
vectors.append({"name": "e71 a signer that is not a string",
"receipts": [edit(R, lambda r: r["chain"].update(signer=["x"]), seal=False)],
"expected": ["signer_unknown"]})
vectors.append({"name": "e72 a bundle whose efficiency is not an object",
"receipts": [edit(BUNDLE, lambda r: r.update(efficiency=[]))], "expected": ["efficiency_missing"]})
vectors.append({"name": "e73 a bundle whose stages are not a list",
"receipts": [edit(BUNDLE, lambda r: r["bundle"].update(stages={}))], "expected": ["malformed"]})
def id_not_a_string():
r = copy.deepcopy(R)
r["receipt_id"] = []
return r
vectors.append({"name": "e74 a receipt id that is not a string",
"receipts": [id_not_a_string()], "expected": ["receipt_id_mismatch"]})
vectors.append({"name": "e75 records that are not an object",
"receipts": v01["receipts"], "records": [], "expected": ["record_mismatch"]})
vectors.append({"name": "e76 a record id that is not a string",
"receipts": [edit(R, lambda r: r["settlement"].update(record_id=[R["settlement"]["record_id"]]))],
"records": v01["records"], "expected": ["record_mismatch"]})
# A record whose answer is not a string, or whose created is a boolean, cannot be
# rehashed -- even when the receipt cites exactly what str() and %.1f would make of it.
def cited_record(field, value):
recs = copy.deepcopy(v01["records"])
rid = R["settlement"]["record_id"]
recs[rid][field] = value
rec = recs[rid]
line = "%s|%s|%.1f" % (rec["key"], rec["answer"], rec["created"])
r = edit(R, lambda r: r["settlement"].update(record_hash="sha256:" + hashlib.sha256(line.encode()).hexdigest()))
return {"receipts": [r], "records": recs}
for name, field, value in [("e77 a record whose answer is not a string", "answer", True),
("e78 a record whose created is a boolean", "created", True)]:
vectors.append(dict(name=name, expected=["record_mismatch"], **cited_record(field, value)))
# The extremes a document may hold (section 4): the largest finite binary64 written
# as a float and as an integer, a float just below the rounding midpoint above it, a
# surrogate pair, and nesting exactly 64 deep. A verifier that refuses the document
# fails every vector in this file.
def nested(k):
x = []
for _ in range(k):
x = [x]
return x
DBL_MAX = 1.7976931348623157e308
vectors.append({"name": "e79 the extremes a document may hold",
"note": [DBL_MAX, int(DBL_MAX), lit("1.7976931348623158e308"), lit('"\\ud83d\\ude00"'),
nested(59)],
"receipts": [], "expected": []})
# --- the order of the reasons reported alone, and each member judged on its value (section 7)
vectors.append({"name": "e80 unknown_major comes before canonical_failure",
"receipts": [edit(R, lambda r: r.update(oer="3.0", extra="x"), seal=False)],
"expected": ["unknown_major"]})
vectors.append({"name": "e81 a forbidden number comes before an unsupported hash",
"receipts": [edit(R, lambda r: (r.update(hash_alg="sha3-512"), r["work"].update(latency_s=0.5)),
seal=False)],
"expected": ["malformed"]})
vectors.append({"name": "e82 an unsupported hash comes before a missing member",
"receipts": [edit(R, lambda r: (r.update(hash_alg="sha3-512"), r.pop("energy")), seal=False)],
"expected": ["missing_capability"]})
vectors.append({"name": "e83 an unsupported signature algorithm stops nothing",
"receipts": [edit(R, lambda r: (r.update(sig_alg="ecdsa-p256"), r["provenance"].update(how="guessed")))],
"expected": ["grade_unknown", "missing_capability"]})
vectors.append({"name": "e84 boundary absent",
"receipts": [edit(R, lambda r: r["energy"].pop("boundary"))], "expected": ["boundary_missing"]})
vectors.append({"name": "e85 a boundary that is not a string",
"receipts": [edit(R, lambda r: r["energy"].update(boundary=5))], "expected": ["boundary_missing"]})
# Extra published keys (see `keys` below): a key that is not a string, and three
# encodings of the identity point, which verifies a signature over any message.
NOT_A_STRING = "ed25519:not-a-string"
vectors.append({"name": "e86 a signer whose published key is not a string",
"receipts": [edit(R, lambda r: r["chain"].update(signer=NOT_A_STRING), seal=False)],
"expected": ["signer_unknown"]})
vectors.append({"name": "e87 receipt id absent",
"receipts": [edit(R, lambda r: r.pop("receipt_id"), seal=False)], "expected": ["malformed"]})
vectors.append({"name": "e88 signer absent",
"receipts": [edit(R, lambda r: r["chain"].pop("signer"), seal=False)], "expected": ["malformed"]})
# --- the remaining tolerance edges: exactly at each edge on its other side
vectors.append({"name": "e89 a sum exactly at its tolerance on the other side",
"receipts": [edit(R, lambda r: only_compute(r, "0.5", "0.500000001"))], "expected": []})
vectors.append({"name": "e90 a bundle exactly at its tolerance on the other side",
"receipts": [edit(BUNDLE, bundle_total(lambda st: st * Decimal("1e-9")))], "expected": []})
ledger_vector("e91 a ledger exactly at its tolerance on the other side",
ledger_with(lambda rest, m: m + m * Decimal("1e-9") - rest), [])
vectors.append({"name": "e92 a floor 1% low and one unit in the 34th digit",
"receipts": [edit(R, floor_at("0.99", "-1e-51"))], "expected": ["floor_mismatch"]})
# --- exactness past 34 digits for the floor, the bundle and the ledger. Each verdict
# flips for a verifier that rounds to 34 digits (IEEE 754 decimal128); the generator
# checks that it does, so the claim cannot rot.
from decimal import Context, ROUND_CEILING, localcontext
def flips_at_34(fn):
"""fn() under exact arithmetic is True (a miss) and under 34 digits False."""
with localcontext(V.EXACT):
exact_miss = fn()
with localcontext(Context(prec=34)):
rounded_miss = fn()
assert exact_miss and not rounded_miss, (exact_miss, rounded_miss)
def floor_past_34(r):
bits, kb, ln2 = V.dec(r["floor"]["bits_committed"]), V.KBOLTZ, V.LN2
for i in range(1, 10000): # a temperature whose floor needs more than 34 digits
t = Decimal("300.%031d" % (i * 7919 % 10**31)) # 34 significand digits
floor = exact(lambda: bits * kb * t * ln2)
with localcontext(Context(prec=34, rounding=ROUND_CEILING)):
fj = +(floor * Decimal("1.01")) # 1% high, rounded away: a miss, exactly
miss = lambda: abs(bits * kb * t * ln2 - fj) > abs(bits * kb * t * ln2) * Decimal("0.01")
with localcontext(Context(prec=34)):
if miss():
continue
flips_at_34(miss)
r["energy"]["temperature_k"] = decimal_string(t)
r["floor"]["floor_j"] = decimal_string(fj)
return
raise AssertionError("no temperature found")
vectors.append({"name": "e93 a floor that misses its tolerance only past 34 digits",
"receipts": [edit(R, floor_past_34)], "expected": ["floor_mismatch"]})
def bundle_past_34(r):
stages = r["bundle"]["stages"]
st = stage_sum(r)
stages.append({"kind": "decision", "receipt_hash": stages[0]["receipt_hash"], "joules": "1e-40"})
r["bundle"]["provenance_root"] = stage_root(stages, r["hash_alg"])
total = decimal_string(exact(lambda: st - st * Decimal("1e-9")))
only_compute(r, total, total)
flips_at_34(lambda: abs(sum(V.dec(s["joules"]) for s in stages) - Decimal(total))
> Decimal("1e-9") * max(Decimal(1), abs(sum(V.dec(s["joules"]) for s in stages))))
vectors.append({"name": "e94 a bundle that misses its tolerance only past 34 digits",
"receipts": [edit(BUNDLE, bundle_past_34)], "expected": ["bundle_sum_mismatch"]})
def ledger_past_34():
v = copy.deepcopy(v01)
L = v["ledger"]
receipts = exact(lambda: sum(V.dec(r["energy"]["joules_total"]) for r in v["receipts"]))
m = V.dec(L["meter_joules"])
L["unallocated_joules"] = "1e-40"
L["carried_forward_joules"] = decimal_string(exact(lambda: m + m * Decimal("1e-9") - receipts))
flips_at_34(lambda: not V._verify_ledger(v["receipts"], L))
return v
ledger_vector("e95 a ledger that misses its tolerance only past 34 digits", ledger_past_34(), ["ledger_mismatch"])
vectors.append({"name": "e96 a receipt served from a record that names none",
"receipts": [edit(R, lambda r: r["settlement"].pop("record_id"))],
"records": v01["records"], "expected": ["record_mismatch"]})
# --- keys a signature cannot rest on (section 5). Each signature is (R = [s]B, S = s),
# which verifies over any message under the identity point -- so a verifier that
# decodes keys leniently accepts it, and the key is the only defect.
def compress(pt):
zi = pow(pt[2], V._P - 2, V._P)
x, y = pt[0] * zi % V._P, pt[1] * zi % V._P
return (y | ((x & 1) << 255)).to_bytes(32, "little")
_GY = 4 * pow(5, V._P - 2, V._P) % V._P
_B = V._decompress(_GY.to_bytes(32, "little"))
S_FORGE = 12345
FORGED = (compress(V._point_mul(S_FORGE, _B)) + S_FORGE.to_bytes(32, "little")).hex()
IDENTITY_KEYS = {
"ed25519:identity": (1).to_bytes(32, "little"),
"ed25519:identity-sign-bit": (1 | (1 << 255)).to_bytes(32, "little"),
"ed25519:identity-y-p-plus-1": (V._P + 1).to_bytes(32, "little"),
}
for name, key in IDENTITY_KEYS.items():
from cryptography.hazmat.primitives.asymmetric import ed25519 as _ed
_ed.Ed25519PublicKey.from_public_bytes(key).verify(bytes.fromhex(FORGED), b"any message") # lenient: accepted
assert not V.strict_key(key), name
for n, (name, why) in enumerate([("ed25519:identity", "of small order"),
("ed25519:identity-sign-bit", "with the sign bit set on x = 0"),
("ed25519:identity-y-p-plus-1", "encoding y = p + 1")]):
vectors.append({"name": "e%d a signer key %s" % (97 + n, why),
"receipts": [edit(R, lambda r, name=name: r["chain"].update(signer=name, signature=FORGED),
seal=False)],
"expected": ["signature_invalid"]})
KEYS = dict(KEYS, **{NOT_A_STRING: 5}, **{k: v.hex() for k, v in IDENTITY_KEYS.items()})
out = {"oer": base["oer"], "draft": base["draft"],
"source": "edge cases for the reasons and number shapes the upstream vectors do not exercise",
"keys": KEYS, "vectors": vectors}
text = json.dumps(out, indent=0, ensure_ascii=False)
for key, literal in LITERALS.items():
assert text.count('"%s"' % key) == 1, key
text = text.replace('"%s"' % key, literal)
open(os.path.join(HERE, "edge_vectors.json"), "w", encoding="utf-8").write(text)
assert V._depth(V.load(open(os.path.join(HERE, "edge_vectors.json"), encoding="utf-8"))) == V.MAX_DEPTH
print("wrote %d edge vectors" % len(vectors))
# Documents every verifier must refuse whole (section 4). The midpoint above the
# largest binary64 rounds to infinity under round-half-even, in either spelling.
MIDPOINT = str(2**1024 - 2**970)
def receipt_with_duplicate_total():
"""One receipt whose energy carries joules_total twice: last-wins readers see the
sealed figure, first-wins readers see 999999.0."""
text = json.dumps(R)
i = text.index('"joules_total": ')
return text[:i] + '"joules_total": "999999.0", ' + text[i:]
UNREADABLE = {
"u01-midpoint-float": MIDPOINT + "e0",
"u02-midpoint-integer": MIDPOINT,
"u03-beyond-binary64": "1e400",
"u04-nan": "NaN",
"u05-infinity": "Infinity",
"u06-negative-infinity": "-Infinity",
"u07-unpaired-surrogate": '"\\ud800"',
"u08-nested-65": json.dumps(nested(63)),
"u09-duplicate-member": '1, "note": 2',
"u10-duplicate-figure-in-a-receipt": None,
"u11-nested-5000": "[" * 4999 + "]" * 4999,
}
UD = os.path.join(HERE, "unreadable")
os.makedirs(UD, exist_ok=True)
for name, note in UNREADABLE.items():
if note is None:
doc = '{"keys": %s, "vectors": [{"name": "x", "receipts": [%s], "expected": []}]}\n' % (
json.dumps(base["keys"]), receipt_with_duplicate_total())
else:
doc = '{"keys": {}, "vectors": [], "note": %s}\n' % note
open(os.path.join(UD, name + ".json"), "w", encoding="utf-8").write(doc)
print("wrote %d unreadable documents" % len(UNREADABLE))