#!/usr/bin/env python3 # ----------------------------------------------------------------------------- # run_consensus_verification.py # # One-command re-run of the AERE formal-verification suite (z3): the QBFT/Falcon # CONSENSUS models AND the CONTRACT SMT models (fund-flow / registry / PQC-verifier # invariants). Reports a single PASS/FAIL plus the verdict-line tally. Each model # exits 0 only if every PROOF is PROVED and every NEGATIVE CONTROL fired, so a green # run means the proofs are discharged AND demonstrably non-vacuous. # # python run_consensus_verification.py # # The verdict-line tally counts the per-check lines each model prints (one line per # property, "[PROVED ] ..." / "[CEX-FOUND] ..." / "[FAILED ] ..."); it is a count # of distinct property checks, not of SUMMARY echoes. # # (The quint/Apalache spec FalconQuorum.qnt is an OPTIONAL secondary cross-check; # see CONSENSUS-VERIFICATION-2026-07-12.md for the `quint run` commands.) # ----------------------------------------------------------------------------- import subprocess, sys, os, re # --- QBFT / Falcon consensus models (unchanged) --- CONSENSUS_MODELS = [ ("QBFT/IBFT 2.0 SAFETY (agreement)", "qbft_safety_smt.py"), ("Falcon LOG-ONLY no-op", "falcon_logonly_noop_smt.py"), ("Falcon BLOCKING safety/liveness/N>=7", "falcon_blocking_smt.py"), ("PQC ACTIVATION transition safety (log-only->blocking + contract-anchored registry)", "qbft_pqc_activation_smt.py"), ("QBFT LIVENESS (partial synchrony)", "qbft_liveness_smt.py"), ("QBFT explicit-Prepare counting (2026-07-14 2nd-client bug+fix)", "qbft_prepare_counting_smt.py"), ("QBFT digest-keyed vote tally (2026-07-14 Finding-A shipped fix)", "qbft_digest_keyed_smt.py"), ("QBFT IBFT 2.0 locking, engine-role model (2026-07-14 Findings D/E)", "qbft_locking_smt.py"), ] # --- CONTRACT SMT models: fund-flow + registry + PQC-verifier invariants (wired in # this loop). Each proves a load-bearing safety invariant by asserting NOT-property # under the real guards (UNSAT) with a firing negative control (guard removed -> SAT). --- CONTRACT_MODELS = [ ("ComputeMarketV3 ESCROW SOLVENCY (bal[T] >= totalLiabilities[T])", "computemarket_smt.py"), ("DestinationSettler NO-ARBITRARY-RECIPIENT + AT-MOST-ONCE + OUTPUT-MATCH", "destinationsettler_smt.py"), ("AccountMigrator ONLY-DESTINATION + ATOMICITY (no custody / no strand)", "migrator_smt.py"), ("PQ FinalityCertificate FAIL-CLOSED accept (quorum/root/size/domain/rotation)", "pqfinality_smt.py"), ("PQ AggregateVerifier FAIL-CLOSED t-of-n authorization (root/digest binding)", "pqaggregate_smt.py"), ("TrustRegistry + VerifiableCredential FAIL-CLOSED compliance trust", "credential_registry_smt.py"), ("RecoveryRegistry APPEND-ONLY + STRICT NONCE + FAIL-CLOSED (Falcon-512)", "recovery_registry_smt.py"), ("AP2MandateVerifier SPEND-AUTH cap + window + L3 executor gate", "ap2_mandate_smt.py"), ("ReputationRegistry8004 M1 author-gate + delta-clamp forward-safety", "reputation_gate_smt.py"), ("VectorStore VERSION-MONOTONICITY + APPEND-ONLY + one-shot receipt", "vectorstore_smt.py"), ("BitstringStatusList REVOCATION MONOTONICITY (terminal) + epoch + frame", "bitstring_status_smt.py"), ] MODELS = CONSENSUS_MODELS + CONTRACT_MODELS _TAG_RE = re.compile(r'^\[(PROVED|CEX-FOUND|FAILED)\s*\]') here = os.path.dirname(os.path.abspath(__file__)) overall = True summary = [] totals = {"PROVED": 0, "CEX-FOUND": 0, "FAILED": 0} for label, fname in MODELS: path = os.path.join(here, fname) print("=" * 78) print(f"### {label} [{fname}]") print("=" * 78) r = subprocess.run([sys.executable, path], capture_output=True, text=True) sys.stdout.write(r.stdout) if r.stderr: sys.stderr.write(r.stderr) for line in r.stdout.splitlines(): m = _TAG_RE.match(line) if m: totals[m.group(1)] += 1 ok = (r.returncode == 0) overall = overall and ok summary.append((label, fname, ok)) print() print("#" * 78) print("### AERE FORMAL-VERIFICATION SUITE -- OVERALL (consensus + contract models)") print("#" * 78) for label, fname, ok in summary: print(f" {'PASS' if ok else 'FAIL'} {label:66} ({fname})") print() print(f" models run: {len(MODELS)} passed: {sum(1 for _,_,ok in summary if ok)}" f" ({len(CONSENSUS_MODELS)} consensus + {len(CONTRACT_MODELS)} contract)") print(f" verdict lines: {totals['PROVED']} PROVED {totals['CEX-FOUND']} CEX-FOUND " f"{totals['FAILED']} FAILED") print("RESULT:", "ALL MODELS PASS (proofs PROVED, negative controls fired)" if overall else "FAILURE -- see model output above") sys.exit(0 if overall else 1)