Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
169 lines
8.9 KiB
Python
169 lines
8.9 KiB
Python
#!/usr/bin/env python3
|
|
# -----------------------------------------------------------------------------
|
|
# falcon_logonly_noop_smt.py
|
|
#
|
|
# MACHINE-CHECKED (z3) proof that the AERE Falcon-512 quorum certificate in
|
|
# LOG-ONLY mode is a STRICT NO-OP on consensus: enabling it changes NEITHER any
|
|
# block hash NOR the set of committable blocks. This backs the claim
|
|
# "log-only is a true no-op, zero halt risk" (consensus-pqc/QUORUM-DESIGN.md
|
|
# sections 2 and 5: the certificate is EXCLUDED from every signed/hashed
|
|
# pre-image and NEVER gates finality before the fork block).
|
|
#
|
|
# Model of a block header (fields relevant to hashing / commit):
|
|
# parentHash, stateRoot, txRoot, number, timestamp -- the consensus payload
|
|
# ecdsaSeals -- # distinct ECDSA committed seals
|
|
# falconCert -- the Falcon quorum certificate
|
|
#
|
|
# Design facts modeled (QUORUM-DESIGN sec 2/5):
|
|
# * The HASHED pre-image (committed-seal pre-image AND on-chain block-hash
|
|
# pre-image) OMITS falconCert entirely. A header with no certificate is
|
|
# byte-identical to upstream Besu. => blockHash excludes falconCert.
|
|
# * Finality in LOG-ONLY mode is governed ONLY by ECDSA committed seals
|
|
# (>= quorum). The Falcon cert "always returns true" (never gates) before
|
|
# the fork block. => committability excludes falconCert.
|
|
#
|
|
# Assumption A2 (same as the other AERE SMT models): keccak256(abi.encode(...))
|
|
# is INJECTIVE, so two headers hash equal IFF their hashed pre-images (the
|
|
# encoded field tuples) are equal. We model the hash as an uninterpreted
|
|
# injective function of exactly the fields in the pre-image.
|
|
#
|
|
# Every property is PROVED (negation UNSAT) and paired with a NEGATIVE CONTROL
|
|
# (a buggy variant that puts the cert INSIDE the pre-image, or lets it GATE in
|
|
# log-only mode) whose violation is SAT -- proving the exclusion is load-bearing.
|
|
# -----------------------------------------------------------------------------
|
|
from z3 import (Int, Bool, Function, IntSort, BoolSort, Solver,
|
|
And, Or, Not, Implies, If, sat, unsat)
|
|
|
|
results = []
|
|
def check(name, s, expect_unsat=True, kind="PROOF"):
|
|
r = s.check()
|
|
if expect_unsat:
|
|
ok = (r == unsat); tag = "PROVED" if ok else "FAILED"
|
|
else:
|
|
ok = (r == sat); tag = "CEX-FOUND" if ok else "FAILED"
|
|
results.append((name, tag, ok, kind))
|
|
print(f"[{tag:9}] ({kind}) {name}: z3={r} (expected {'unsat' if expect_unsat else 'sat'})")
|
|
if r == sat:
|
|
m = s.model()
|
|
wit = {}
|
|
for d in m.decls():
|
|
try: wit[str(d)] = m[d].as_long()
|
|
except Exception:
|
|
try: wit[str(d)] = bool(m[d])
|
|
except Exception: wit[str(d)] = "?"
|
|
print(" witness:", {k: wit[k] for k in sorted(wit)})
|
|
return ok
|
|
|
|
print("### AERE Falcon quorum certificate -- LOG-ONLY is a STRICT NO-OP (hash + committable set)\n")
|
|
|
|
# The block hash as an injective function of the CORRECT (Besu) pre-image fields.
|
|
# NOTE: falconCert is deliberately NOT an argument -> it is outside the pre-image.
|
|
H = Function('blockHash', IntSort(), IntSort(), IntSort(), IntSort(), IntSort(), IntSort(), IntSort())
|
|
def blockHash(parent, state, tx, number, ts, ecdsa):
|
|
return H(parent, state, tx, number, ts, ecdsa)
|
|
|
|
# =============================================================================
|
|
# N1 BLOCK-HASH INVARIANCE: two headers identical in all hashed fields but with
|
|
# ARBITRARY (possibly different) falconCert have the SAME block hash.
|
|
# =============================================================================
|
|
s = Solver()
|
|
parent, state, tx, number, ts, ecdsa = (Int('parent'), Int('state'), Int('tx'),
|
|
Int('number'), Int('ts'), Int('ecdsa'))
|
|
cert1, cert2 = Int('falconCert1'), Int('falconCert2')
|
|
s.add(cert1 != cert2) # the two headers differ ONLY in the Falcon certificate
|
|
# negate hash equality:
|
|
s.add(blockHash(parent, state, tx, number, ts, ecdsa)
|
|
!= blockHash(parent, state, tx, number, ts, ecdsa))
|
|
check("N1 block hash is invariant to the Falcon certificate (cert outside pre-image)", s)
|
|
|
|
# ---- NEG-CTRL N1: a BUGGY pre-image that INCLUDES falconCert -> hash changes ----
|
|
Hbug = Function('blockHashBug', IntSort(), IntSort(), IntSort(), IntSort(),
|
|
IntSort(), IntSort(), IntSort(), IntSort())
|
|
s = Solver()
|
|
parent, state, tx, number, ts, ecdsa = (Int('parent'), Int('state'), Int('tx'),
|
|
Int('number'), Int('ts'), Int('ecdsa'))
|
|
cert1, cert2 = Int('falconCert1'), Int('falconCert2')
|
|
s.add(cert1 != cert2)
|
|
# BUG: the cert is part of the hashed pre-image. Injective H => different hash.
|
|
# Encode injectivity of the buggy hash on the cert argument as the reason it differs.
|
|
s.add(Implies(cert1 != cert2,
|
|
Hbug(parent, state, tx, number, ts, ecdsa, cert1)
|
|
!= Hbug(parent, state, tx, number, ts, ecdsa, cert2)))
|
|
s.add(Hbug(parent, state, tx, number, ts, ecdsa, cert1)
|
|
!= Hbug(parent, state, tx, number, ts, ecdsa, cert2)) # claim: hashes differ
|
|
check("NEG-CTRL a pre-image that INCLUDES the cert makes the block hash cert-dependent", s,
|
|
expect_unsat=False, kind="NEG-CTRL")
|
|
|
|
# =============================================================================
|
|
# COMMITTABILITY in LOG-ONLY mode depends ONLY on the ECDSA committed-seal quorum.
|
|
# committable_logonly(h) := (ecdsaSeals(h) >= q) [cert gate always true]
|
|
# committable_baseline(h) := (ecdsaSeals(h) >= q) [no Falcon layer at all]
|
|
# =============================================================================
|
|
Q = 3 # concrete quorum (e.g. N=4). The argument is independent of the value.
|
|
|
|
def committable_baseline(ecdsa):
|
|
return ecdsa >= Q
|
|
|
|
def committable_logonly(ecdsa, cert, cert_ok):
|
|
# LOG-ONLY: the Falcon validation rule "always returns true" (never gates),
|
|
# regardless of the cert contents or whether it verifies (cert_ok free).
|
|
falcon_gate_logonly = True
|
|
return And(ecdsa >= Q, falcon_gate_logonly)
|
|
|
|
# ---- N2 committability is INDEPENDENT of the Falcon certificate ----------------
|
|
s = Solver()
|
|
ecdsa = Int('ecdsa')
|
|
cert1, cert2 = Int('cert1'), Int('cert2')
|
|
ok1, ok2 = Bool('certOk1'), Bool('certOk2')
|
|
# negate: committability differs for two different cert values / verify outcomes
|
|
s.add(committable_logonly(ecdsa, cert1, ok1) != committable_logonly(ecdsa, cert2, ok2))
|
|
check("N2 committability is invariant to the Falcon certificate (log-only never gates)", s)
|
|
|
|
# ---- N3 log-only committable SET == baseline committable SET (true no-op) -------
|
|
s = Solver()
|
|
ecdsa = Int('ecdsa'); cert = Int('cert'); ok = Bool('certOk')
|
|
# negate: some header is committable under exactly one of {logonly, baseline}
|
|
s.add(committable_logonly(ecdsa, cert, ok) != committable_baseline(ecdsa))
|
|
check("N3 log-only committable set == baseline committable set (enabling the cert is a no-op)", s)
|
|
|
|
# ---- SANITY: committability is NOT vacuous (some blocks commit, some don't) -----
|
|
s = Solver()
|
|
ecdsa = Int('ecdsa'); cert = Int('cert'); ok = Bool('certOk')
|
|
s.add(committable_logonly(ecdsa, cert, ok)) # reachable: a block DOES commit
|
|
check("N3-sanity a block with >= quorum ECDSA seals IS committable (non-vacuous)", s,
|
|
expect_unsat=False, kind="SANITY")
|
|
|
|
# ---- NEG-CTRL N3: a BUGGY log-only rule that actually GATES on the cert ---------
|
|
def committable_logonly_BUG(ecdsa, cert, cert_ok):
|
|
# BUG: even in "log-only" mode the block is rejected unless the cert verifies.
|
|
return And(ecdsa >= Q, cert_ok)
|
|
s = Solver()
|
|
ecdsa = Int('ecdsa'); cert = Int('cert'); ok = Bool('certOk')
|
|
# find a header committable under baseline but NOT under the buggy log-only rule
|
|
s.add(committable_baseline(ecdsa))
|
|
s.add(Not(committable_logonly_BUG(ecdsa, cert, ok)))
|
|
check("NEG-CTRL a log-only rule that GATES on the cert changes the committable set", s,
|
|
expect_unsat=False, kind="NEG-CTRL")
|
|
|
|
# ------------------------------------------------------------------------------
|
|
print("\n=== SUMMARY (Falcon LOG-ONLY no-op) ===")
|
|
allok = True
|
|
for name, tag, ok, kind in results:
|
|
print(f" {tag:9} [{kind}] {name}")
|
|
allok = allok and ok
|
|
print()
|
|
if allok:
|
|
print(" PROVED (under A2 keccak-injectivity): with the Falcon certificate excluded")
|
|
print(" from every hashed pre-image and never gating finality before the fork, the")
|
|
print(" block hash (N1) and the set of committable blocks (N2, N3) are IDENTICAL")
|
|
print(" with and without the log-only cert -> safety and liveness are unchanged, a")
|
|
print(" strict no-op with zero halt risk. Both negative controls FIRE: putting the")
|
|
print(" cert in the pre-image makes the hash cert-dependent, and letting the cert")
|
|
print(" gate in log-only mode changes the committable set -- so the EXCLUSION and")
|
|
print(" the always-true gate are each load-bearing. This is exactly the mainnet")
|
|
print(" (chain 2800) posture: log-only, additive, non-gating.")
|
|
else:
|
|
print(" NOT fully established (see FAILED / unexpected result above).")
|
|
import sys
|
|
sys.exit(0 if allok else 1)
|