Dated corrections (2026-10-27): formal-consensus/RULEAZA-TOT.md translated into English and dated (it stated, without a date, facts of the chain of August 2026); the models print the chain facts of their time with the date, or the facts of today (labels and printed strings only, the logic and the verdicts unchanged: 37 of 37 models pass); README: 37 models counted on 2026-10-27 and the reproduction pointer to aere-docs REPRODUCE.md section 3b

This commit is contained in:
Aere Network 2026-10-27 15:01:25 +02:00
parent 9b2a69ab6b
commit 6d24576357
8 changed files with 149 additions and 133 deletions

View File

@ -55,8 +55,8 @@ Two more limits, both of which cut against claims made in this repository:
## Layout
- `formal-consensus/` Z3 / SMT models of consensus and contract safety properties (30 Python
models plus a Quint spec `FalconQuorum.qnt`), driven by `run_consensus_verification.py`. These
- `formal-consensus/` Z3 / SMT models of consensus and contract safety properties (37 Python
models, counted on 2026-10-27, plus a Quint spec `FalconQuorum.qnt`), driven by `run_consensus_verification.py`. These
cover QBFT safety and liveness, the money-contract invariants, and a PROPOSED hybrid
dual-quorum activation that is modelled research and is NOT running on chain 2800, and the
invariants. `CONSENSUS-VERIFICATION-2026-07-12.md` documents the results.
@ -84,8 +84,9 @@ python run_consensus_verification.py
```
The STARK references are cross-checked against their ground-truth vectors; see each
`spec-*.md` and the `test_*.py` files. Full commands and expected outputs are in the `aere-docs`
repository (`REPRODUCE.md`).
`spec-*.md` and the `test_*.py` files. Full commands and expected outputs, dated, are in the `aere-docs`
repository (`REPRODUCE.md`; its section 3b gives the result of the command above as measured on 2026-10-27, and
the older runs it records use the paths of the development tree).
## What is deliberately not here

View File

@ -1,83 +1,85 @@
# RULEAZA-TOT: verificarea formala a consensului AERE, un capat la altul
# RULEAZA-TOT: the formal verification of AERE consensus, end to end
Rularea completa a tot ce se poate verifica automat pe consensul AERE (QBFT / IBFT 2.0,
chain 2800), cu doua metode independente:
*Translated into English and dated on 2026-10-27. Until that date this document was in Romanian and stated, without a date,
facts that were true only of the chain of August 2026 (a set of nine validators, an anchor minimum of three); the
corrections are marked below, and the results it records keep the date they were measured on.*
- **SMT (z3)** parametric, in acest dosar (`formal-consensus/*_smt.py`): dovedeste fiecare
proprietate aratand ca negatia ei e UNSAT, plus un control negativ care planteaza
incalcarea si trebuie sa iasa SAT. Scaleaza la N=9 (flota reala).
- **TLA+ / TLC** exhaustiv, in `aerenew/formal-tla/`: verifica prin explorare de stari la
scara mica (N=4), unde combinatoria e suficienta.
A complete run of everything that can be checked automatically about AERE consensus (QBFT / IBFT 2.0, chain 2800), with two
independent methods:
Regula peste tot: **niciun model nu se raporteaza verde daca nu poate iesi ROSU.** Fiecare
proprietate are un control negativ rulat.
- **SMT (z3)**, parametric, in this directory (`formal-consensus/*_smt.py`): each property is proved by showing that its
negation is UNSAT, plus a negative control that plants the violation and must come back SAT. The models scale to N=9,
the validator set of 2026-08-24, when the table below was written; the set has had ten validators since 2026-09-11, and
the models state the N each one is run at.
- **TLA+ / TLC**, exhaustive, in `formal-tla/` of the development tree (not in this repository): it explores the state
space at a small scale (N=4), where the combinatorics is enough.
The rule everywhere: **no model is reported green unless it can come out RED.** Every property has a negative control
that is run.
---
## 1. Suita SMT (z3) - o singura comanda
## 1. The SMT suite (z3): one command
```
cd aerenew/publish-bundle/aere-research/formal-consensus
cd formal-consensus
python run_consensus_verification.py
```
Ruleaza TOATE modelele `*_smt.py` din dosar (garda de completitudine refuza sa iasa verde
daca vreun model prezent nu e cablat). Tipareste PASS/FAIL per model, timpul fiecaruia, si
tally-ul de linii de verdict.
It runs ALL the `*_smt.py` models in this directory (the completeness guard refuses a green result if a model that is
present is not wired). It prints PASS / FAIL per model, the time of each, and the tally of verdict lines.
**Masurat 2026-10-07** (Windows, python 3.14.4 / z3 4.16.0; timpii variaza cu masina):
**Measured 2026-10-07** (Windows, Python 3.14.4 / z3 4.16.0; the times vary with the machine):
```
models run: 37 passed: 37 (16 consensus + 11 contract + 10 application)
verdict lines: 301 PROVED 159 CEX-FOUND 0 FAILED
wall time: ~37s total (cel mai lent: qbft_safety_smt.py ~20s)
wall time: ~37s total (slowest: qbft_safety_smt.py ~20s)
coverage: 37 of 37 *_smt.py files wired
RESULT: ALL MODELS PASS (proofs PROVED, negative controls fired)
```
Istoria cifrelor, datata: 2026-08-24, 35 de modele (14 consens), 282 PROVED / 149 CEX-FOUND, ~39 s;
The history of the figures, dated: 2026-08-24, 35 models (14 consensus), 282 PROVED / 149 CEX-FOUND, ~39 s;
2026-09-02, + `pq_message_enforcement_smt.py` (36 of 36); 2026-10-07, + `anchor_rewrite_bound_roundfree_smt.py`
(37 of 37; 13 dovezi, 2 leme, 4 martori, 1 definitie, 8 controale negative; limita de rescriere 32 / 33 sub modelul
fara runda, ca functie de K_eff si de cheile PQ tinute; vezi `research/rewrite-bound-round-free-seal-2026-10-07.md`
si `anchor_rewrite_bound_roundfree_smt.RESULT.txt`).
(37 of 37; 13 proofs, 2 lemmas, 4 witnesses, 1 definition, 8 negative controls; the rewrite bound is 32 / 33 under the
round-free model, as a function of K_eff and of the post-quantum keys held; see
`research/rewrite-bound-round-free-seal-2026-10-07.md` and `anchor_rewrite_bound_roundfree_smt.RESULT.txt`).
Cele 16 modele de consens (14 pe 24 august, + 1 pe 2 septembrie, + 1 pe 7 octombrie):
The 16 consensus models (14 on 24 August, + 1 on 2 September, + 1 on 7 October):
| model | ce dovedeste | N |
| model | what it proves | N |
|---|---|---|
| `qbft_safety_smt.py` | agreement (quorum-intersection unbounded; one-round + cross-round locking) | 4,5,7,10,13,16 |
| `qbft_liveness_smt.py` | progres post-GST (f+1 runde ating un proposer onest) | 4,5,7 |
| `qbft_locking_smt.py` | locking IBFT 2.0 pe rolurile motorului (view-change / round-change) | 4,5,7 |
| `qbft_prepare_counting_smt.py`, `qbft_digest_keyed_smt.py` | numararea voturilor (bug+fix 2026-07-14) | mic |
| `falcon_blocking_smt.py`, `anchor_blocking_quorum_smt.py` | pragul de sigilii pe ancora (K=3 din 9) | 9 |
| `qbft_pqc_activation_smt.py` | tranzitia log-only -> blocant | - |
| **`partition_safety_smt.py`** (NOU) | **partitii de retea: split-brain, starvatie, vindecare** | **9 param.** |
| **`anchor_viewchange_smt.py`** (NOU) | **o schimbare de runda pe o ancora nu da doua certificate valide** | **9** |
| `pqanchor_ceiling_monotonicity_smt.py` | plafonul de urgenta doar coboara K | - |
| `registry_index_binding_smt.py`, `registry_rotation_coverage_smt.py` | registrul de chei pe inaltime | - |
| **`anchor_rewrite_bound_roundfree_smt.py`** (2026-10-07) | **limita de rescriere sub adversarul cu toate cheile clasice: 32 de blocuri (ancora + 31), 33 sub exceptia din erata AIP-22 (fratele nedecis, bunicul comun); marginita exact cand cheile PQ tinute j < K_eff (K_eff = 7 pe validator, 1 pe urmaritorul publicat cu plafon); 128 / 129 in fereastra datata cu interval 128; punctul de referinta fixeaza prefixul (lantul de hash-uri desfasurat 1280 de inaltimi); `--plant-bounds` = controlul controlului** | 10, orice K_eff >= 1 |
| `qbft_safety_smt.py` | agreement (quorum intersection unbounded; one-round + cross-round locking) | 4,5,7,10,13,16 |
| `qbft_liveness_smt.py` | progress after GST (f+1 rounds reach an honest proposer) | 4,5,7 |
| `qbft_locking_smt.py` | IBFT 2.0 locking on the engine roles (view change / round change) | 4,5,7 |
| `qbft_prepare_counting_smt.py`, `qbft_digest_keyed_smt.py` | the counting of votes (bug and fix of 2026-07-14) | small |
| `falcon_blocking_smt.py`, `anchor_blocking_quorum_smt.py` | the anchor seal threshold of 2026-08-15 (K=3 of 9; the minimum is 7 of 10 since block 20,715,632) | 9 |
| `qbft_pqc_activation_smt.py` | the log-only -> blocking transition | - |
| **`partition_safety_smt.py`** (new on 2026-08-24) | **network partitions: split brain, starvation, healing** | **9, parametric** |
| **`anchor_viewchange_smt.py`** (new on 2026-08-24) | **a round change at an anchor does not give two valid certificates, in the model, under its finalized-block guard (the code has no such guard: note added 2026-10-01)** | **9** |
| `pqanchor_ceiling_monotonicity_smt.py` | the emergency ceiling only lowers K | - |
| `registry_index_binding_smt.py`, `registry_rotation_coverage_smt.py` | the key registry by height (the registries of 2026-08-15) | - |
| **`anchor_rewrite_bound_roundfree_smt.py`** (2026-10-07) | **the rewrite bound under the adversary holding every classical key: 32 blocks (the anchor + 31), 33 under the exception of the AIP-22 erratum (the undecided sibling, the common grandparent); bounded exactly when the post-quantum keys held j < K_eff (K_eff = 7 on a validator, 1 on the published follower with its ceiling); 128 / 129 in the dated window with interval 128; the reference point pins the prefix (the hash chain unrolled over 1280 heights); `--plant-bounds` is the control of the control** | 10, any K_eff >= 1 |
> Nota: cele trei modele de registru/plafon existau in dosar din 15-19 august dar NU erau
> cablate in rulator (garda de completitudine il facea sa iasa cu cod 2). Cablate pe 24 august
> impreuna cu cele doua modele noi.
> Note: the three registry / ceiling models were in the directory from 15 to 19 August but were NOT wired into the runner
> (the completeness guard made it exit with code 2). They were wired on 24 August together with the two new models.
---
## 2. TLA+ / TLC exhaustiv - partitiile de retea (NOU, 24 august)
## 2. TLA+ / TLC, exhaustive: network partitions (new on 24 August)
Modelul `aerenew/formal-tla/QBFTPartition.tla` face partitia un DEFECT modelat explicit
(un predicat pe livrarea mesajelor intre grupuri) si o verifica exhaustiv la N=4. Sase
configuratii, fiecare cu perechea ei pozitiv/negativ.
The model `formal-tla/QBFTPartition.tla` (development tree) makes the partition an explicitly modelled FAULT (a predicate
on the delivery of messages between groups) and checks it exhaustively at N=4. Six configurations, each with its positive
/ negative pair.
### Rularea (WSL, mult mai rapid decat pe Windows)
### The run (much faster under Linux, or WSL on Windows, than natively on Windows)
Scrie un script, copiaza-l, ruleaza-l fara ghilimele inline (comenzile inline se mangleaza
prin wsl.exe). Toate rularile folosesc `-deadlock` fiindca protocolul se TERMINA in mod normal
(toti au decis) si terminarea nu e un defect:
Write a script, copy it, run it without inline quotes. Every run uses `-deadlock`, because the protocol TERMINATES
normally (everyone has decided) and termination is not a defect:
```bash
# copie dosarul in /root (rulare rapida, in afara /mnt)
AERE_REPO=/calea/catre/clona/depozitului # radacina clonei tale; dosarul formal-tla/ sta direct sub ea
# copy the directory outside any mounted Windows drive (a faster run)
AERE_REPO=/path/to/the/clone # the root of your clone; the formal-tla/ directory sits directly under it
mkdir -p /root/ftla
cp -f "$AERE_REPO"/formal-tla/*.tla /root/ftla/
cp -f "$AERE_REPO"/formal-tla/*.cfg /root/ftla/
@ -89,62 +91,61 @@ for CFG in MCpart_safety MCpart_safety_witness MCpart_safety_negctrl \
done
```
Lanseaza din PowerShell:
`MSYS_NO_PATHCONV=1 wsl.exe -d Ubuntu-24.04 -- bash /mnt/c/.../script.sh`
### Results measured 2026-08-24 (WSL, OpenJDK 21, exhaustive, 0 states left in the queue)
### Rezultate masurate 2026-08-24 (WSL, OpenJDK 21, exhaustiv, 0 stari ramase in coada)
| config | ce verifica | asteptat | rezultat | timp |
| config | what it checks | expected | result | time |
|---|---|---|---|---|
| `MCpart_safety` | 3-1, quorum 3, heal: SAFETY se pastreaza | fara eroare | **No error** (1866 stari) | ~3s |
| `MCpart_safety_witness` | acelasi, invariant `NoCommit` | VIOLARE (commit e atins) | **NoCommit violated** -> `committed={a}` | ~2s |
| `MCpart_safety_negctrl` | 2-2, quorum COBORAT la 2 | VIOLARE (fork) | **NoFork violated** -> `committed={a,b}` (v1->a, v3->b) | ~4s |
| `MCpart_noprogress` | 2-2, quorum 3, FARA vindecare, invariant `NoCommit` | fara eroare | **No error** (81 stari; nimic nu se finalizeaza) | ~2s |
| `MCpart_liveness` | 2-2, quorum 3, vindecare, `EventualCommit` | fara eroare | **No error** (liveness revine dupa heal) | ~3s |
| `MCpart_liveness_negctrl` | 2-2, quorum 3, FARA vindecare, `EventualCommit` | VIOLARE | **EventualCommit violated** (stuttering, `committed={}`) | ~2s |
| `MCpart_safety` | 3-1, quorum 3, heal: SAFETY holds | no error | **No error** (1866 states) | ~3s |
| `MCpart_safety_witness` | the same, invariant `NoCommit` | VIOLATION (a commit is reached) | **NoCommit violated** -> `committed={a}` | ~2s |
| `MCpart_safety_negctrl` | 2-2, quorum LOWERED to 2 | VIOLATION (fork) | **NoFork violated** -> `committed={a,b}` (v1->a, v3->b) | ~4s |
| `MCpart_noprogress` | 2-2, quorum 3, NO healing, invariant `NoCommit` | no error | **No error** (81 states; nothing finalizes) | ~2s |
| `MCpart_liveness` | 2-2, quorum 3, healing, `EventualCommit` | no error | **No error** (liveness returns after the heal) | ~3s |
| `MCpart_liveness_negctrl` | 2-2, quorum 3, NO healing, `EventualCommit` | VIOLATION | **EventualCommit violated** (stuttering, `committed={}`) | ~2s |
Cele trei perechi acopera exact intrebarile cerute:
- **SAFETY se pastreaza in ambele parti**: `MCpart_safety` verde, si non-vacuu prin `witness`
(partea majoritara chiar finalizeaza). Controlul negativ `safety_negctrl` arata ca ce
opreste fork-ul e quorum-ul ceil(2N/3): coborat la 2, cele doua parti finalizeaza `a` si `b`.
- **LIVENESS se pierde in grupul fara quorum**: `MCpart_noprogress` (nimic nu se finalizeaza
intr-o partitie 2-2 nevindecata).
- **LIVENESS revine la vindecare**: `MCpart_liveness` verde; controlul negativ
`liveness_negctrl` arata ca fara pasul de vindecare `EventualCommit` PICA (heal e cauza).
The three pairs answer exactly the questions asked:
- **SAFETY holds on both sides**: `MCpart_safety` is green, and non-vacuous through `witness` (the majority side does
finalize). The negative control `safety_negctrl` shows that what stops the fork is the ceil(2N/3) quorum: lowered to 2,
the two sides finalize `a` and `b`.
- **LIVENESS is lost in the group without a quorum**: `MCpart_noprogress` (nothing finalizes in an unhealed 2-2
partition).
- **LIVENESS returns on healing**: `MCpart_liveness` is green; the negative control `liveness_negctrl` shows that without
the healing step `EventualCommit` FAILS (the heal is the cause).
---
## 3. TLA+ / TLC - modelul QBFT complet (agreement + view-change + echivocatie)
## 3. TLA+ / TLC: the complete QBFT model (agreement + view change + equivocation)
`aerenew/formal-tla/QBFT.tla` cu `MCsafety.cfg` (N=4) / `MCsafety7.cfg` (N=7) si
`MCliveness.cfg`. **Masurat 2026-07-19 si 2026-08-24: aceste configuratii NU se termina** in
bugetul local (spatiul de stari e de ordinul zecilor de milioane; `MCliveness` a generat
543k stari distincte in 197s cu 527k inca in coada). Ce e stabilit acolo e un martor
explicit-state partial (9,35 milioane de stari fara violare pe N=4 round-0), NU o verificare
completa. Vezi `TLC-RUN-REPORT.md`. Miezul all-N (quorum-intersection, agreement sub locking)
e deja dovedit pentru ORICE N de suita SMT; TLA+ e metoda independenta, iar valoarea lui la
partitii este ca `QBFTPartition.tla` chiar SE TERMINA exhaustiv (single-height), spre
deosebire de modelul complet.
`formal-tla/QBFT.tla` (development tree) with `MCsafety.cfg` (N=4) / `MCsafety7.cfg` (N=7) and `MCliveness.cfg`.
**Measured 2026-07-19 and 2026-08-24: these configurations do NOT terminate** within the local budget (the state space is
in the tens of millions; `MCliveness` generated 543k distinct states in 197 s with 527k still queued). What is established
there is a partial explicit-state witness (9.35 million states without a violation at N=4 round 0), NOT a complete
check (`TLC-RUN-REPORT.md`, development tree). The all-N core (quorum intersection, agreement under locking) is already
proved for ANY N by the SMT suite; TLA+ is the independent method, and its value for partitions is that
`QBFTPartition.tla` does TERMINATE exhaustively (single height), unlike the complete model.
---
## 4. Cross-check optional: quint / Apalache
## 4. Optional cross-check: quint / Apalache
`FalconQuorum.qnt` e un cross-check secundar (vezi `CONSENSUS-VERIFICATION-2026-07-12.md`
pentru comenzile `quint run`).
`FalconQuorum.qnt` is a secondary cross-check (see `CONSENSUS-VERIFICATION-2026-07-12.md` for the `quint run`
commands).
---
## Granita cinstita (se citeste, nu se sare)
## The honest boundary (read it, do not skip it)
- Model checking **nu e demonstratie completa.** SMT dovedeste combinatoria design-ului
(numararea voturilor, intersectia quorum-urilor, legarea certificatului), nu bytecode-ul
Besu/EVM. TLC verifica exhaustiv doar configuratia finita enuntata (N=4 la partitii).
- SMT parametric la N=9 dovedeste proprietatea pentru **acel** N; miezul aritmetic
(quorum-intersection, 2q>N) e unbounded in N.
- Consensul chain 2800 comita cu **ECDSA clasic** secp256k1; ancora PQ e ADITIVA. Nimic de
aici nu implica "consens post-cuantic".
- Primitivele criptografice (injectivitatea keccak, soliditatea gateway-ului SP1, validarea
sigiliului Falcon) sunt tratate ca `[VERIFY]`, modelate, nu re-dovedite.
- Ancora foloseste K=3 = **f+1**, NU un quorum. Unicitatea certificatului vine din legarea la
blocul finalizat (dovada `anchor_viewchange_smt.py`), nu din intersectia sigiliilor.
- Model checking **is not a complete proof.** SMT proves the combinatorics of the design (vote counting, quorum
intersection, the binding of the certificate), not the Besu / EVM bytecode. TLC checks exhaustively only the finite
configuration stated (N=4 for partitions).
- Parametric SMT at N=9 proves the property for **that** N; the arithmetic core (quorum intersection, 2q > N) is
unbounded in N.
- When these models were written (July to October 2026), chain 2800 committed its blocks with **classical** secp256k1
ECDSA seals and the post-quantum anchor was ADDITIVE; nothing here implies "post-quantum consensus". The chain of today
is described in the aere-node SPEC.md. (Corrected 2026-10-27: this point was stated in the present tense.)
- The cryptographic primitives (keccak injectivity, the soundness of the SP1 gateway, the validation of the Falcon seal)
are treated as `[VERIFY]`: modelled, not re-proved.
- In the models of August 2026 the anchor used K=3 = **f+1**, NOT a quorum; since block 20,715,632 the minimum is 7 of
10 per scheme, as many as the QBFT quorum of the ten validators (corrected 2026-10-27: this point was stated in the
present tense). In the model, the uniqueness of the certificate comes from its binding to the finalized block, the
guard of `anchor_viewchange_smt.py`, not from an intersection of seals; the client code has no such guard (note added
2026-10-01 in the runner).

View File

@ -155,9 +155,12 @@ class Block:
falcon_ok = If(is_anchor(self.h), anykey >= self.K_eff(), BoolVal(True))
return And(self.qbft >= QBFT_Q, falcon_ok)
print("### AERE anchor BLOCKING-QUORUM SAFETY -- fork at 14,050,000, K=3, N=9, q=6\n")
print("### AERE anchor THRESHOLD SAFETY on the chain of 2026-08-15 (K=3, N=9, q=6, registries R1 of 7 keys and R2 of 9)")
print("### modelled for anchor heights >= 14,050,000, called 'the fork' below. Corrected 2026-10-27: that height is the bound of")
print("### this model, not a blocking fork: the property armed there changed no enforcement (correction of 2026-08-19), and the K=3")
print("### step is from 13,034,000. Today: ten validators since 2026-09-11, minimum 7 per scheme since block 20,715,632.\n")
print(f" anchor grid: every {ANCHOR_INTERVAL} blocks from {ANCHOR_START}; "
f"fork {FORK_BLOCKING} is {'ON' if (FORK_BLOCKING-ANCHOR_START)%ANCHOR_INTERVAL==0 else 'OFF'} the grid "
f"model bound {FORK_BLOCKING} is {'ON' if (FORK_BLOCKING-ANCHOR_START)%ANCHOR_INTERVAL==0 else 'OFF'} the grid "
f"((14050000-13014000)/32 = {(FORK_BLOCKING-ANCHOR_START)//ANCHOR_INTERVAL})\n")
# =============================================================================
@ -165,14 +168,14 @@ print(f" anchor grid: every {ANCHOR_INTERVAL} blocks from {ANCHOR_START}; "
# =============================================================================
s = Solver()
s.add(Int('r') == (FORK_BLOCKING - ANCHOR_START) % ANCHOR_INTERVAL, Int('r') != 0)
check("S0a CONFIG: the blocking-fork height 14,050,000 lies ON the anchor grid "
check("S0a CONFIG: the model bound 14,050,000 lies ON the anchor grid "
"(it is itself an anchor height)", s)
s = Solver()
h = Int('h')
s.add(h >= FORK_BLOCKING, sched_K(h) != K_TARGET)
check("S0b SCHEDULE (all h >= fork): the min-seals schedule pins K == 3 at every "
"blocking-era height (13034000:3 step is below the fork)", s)
check("S0b SCHEDULE (all h >= 14,050,000, schedule of 2026-08-15): the min-seals schedule pins K == 3 at every "
"modelled height (the 13034000:3 step is below the bound)", s)
s = Solver()
h = Int('h')
@ -185,8 +188,8 @@ check("S0c REGISTRY PARTITION (all h): every height from 13,014,000 on is covere
s = Solver()
h = Int('h')
s.add(h >= FORK_BLOCKING, Not(h >= REG2_START))
check("S0d REGISTRY AT FORK (all h >= fork): the active registry in the blocking "
"era is the 9-key registry (fork 14,050,000 > rotation 13,600,000)", s)
check("S0d REGISTRY AT THE BOUND (all h >= 14,050,000): the active registry in the "
"modelled range is the 9-key registry (14,050,000 > rotation 13,600,000)", s)
# =============================================================================
# S1 -- THE INVARIANT (positive result). An anchor block at h >= fork, with the
@ -198,7 +201,7 @@ s = Solver(); s.add(b.wf())
s.add(b.h >= FORK_BLOCKING, is_anchor(b.h), Not(b.ceil_set))
s.add(b.finalized())
s.add(b.distinct_eligible_valid() <= 2)
check("S1 BLOCKING-QUORUM SAFETY: post-fork ANCHOR block finalized with <= 2 "
check("S1 THRESHOLD SAFETY: post-fork ANCHOR block finalized with <= 2 "
"distinct valid eligible Falcon seals is IMPOSSIBLE (K=3 floor holds)", s)
# same, with the ceiling engaged but at/above K: still no hole below 3
@ -338,21 +341,22 @@ s = Solver()
s.add(c >= 0, w == If(c <= 2, c, 2)) # planted cap 2 < K
s.add(c >= K_TARGET, w < K_TARGET)
check("S7b NEG-CTRL: PLANT a cap of 2 < K -> a 3-seal certificate is written short "
"of the quorum (why maxSeals below the schedule K is refused at load)", s,
"of K (why maxSeals below the schedule K is refused at load)", s,
expect_unsat=False, kind="NEG-CTRL")
# =============================================================================
print("\n=== SUMMARY (anchor BLOCKING-QUORUM SAFETY) ===")
print("\n=== SUMMARY (anchor THRESHOLD SAFETY, chain of 2026-08-15) ===")
allok = True
for name, tag, ok, kind in results:
print(f" {tag:9} [{kind}] {name}")
allok = allok and ok
print()
if allok:
print(" PROVED: with the blocking fork active (h >= 14,050,000) no anchor block")
print(" PROVED: on the chain of 2026-08-15, at anchor heights >= 14,050,000 (the bound of this model; that")
print(" height changed no enforcement, correction of 2026-08-19) no anchor block")
print(" can be finalized with fewer than K=3 valid Falcon seals from DISTINCT")
print(" signers of the registry active at that height (the 9-key registry, since")
print(" the fork lies above the 13,600,000 rotation), and non-anchor blocks")
print(" the bound lies above the 13,600,000 rotation), and non-anchor blocks")
print(" require no seals at all (proved in both directions). The mandated")
print(" negative control FIRES: a planted rule permitting 2 seals finalizes an")
print(" anchor block with exactly 2 seals (SAT), so the K>=3 guard is load-")
@ -362,7 +366,8 @@ if allok:
print(" (and is the single designed path below 3); the maxSeals=5 write cap can")
print(" never starve a certificate below K, and a planted cap of 2 does.")
print(" BOUNDARY: design combinatorics of the finalization predicate, not Besu")
print(" bytecode, not the live chain; registries modelled as index sets.")
print(" bytecode, not the live chain; registries modelled as index sets. Today the set has ten validators")
print(" (since 2026-09-11) and the minimum is 7 per scheme (since block 20,715,632): not modelled here.")
else:
print(" NOT fully established (see FAILED / unexpected result above).")
import sys

View File

@ -411,7 +411,7 @@ if allok:
print(" blocks (N in {4,5,7}) -- and LIVE at the fault bound (N-f >= quorum, all")
print(" N). The N>=7 requirement is machine-checked: N=7 is the smallest set that")
print(" is BOTH safe (f>=2) and live (N-2>=quorum) against 2 Falcon faults. It is")
print(" also the next BFT-optimal 3f+1 size, and unlike the current N=5 (zero")
print(" also the next BFT-optimal 3f+1 size, and unlike N=5, the mainnet size when this model was written (2026-07-12; zero")
print(" single-fault margin) it leaves margin > 0 over quorum for a single fault. At")
print(" N in {4,5} two Falcon faults drop the correct set below quorum and the")
print(" post-fork chain STALLS (shown reachable). Negative controls FIRE: dropping")
@ -426,10 +426,13 @@ if allok:
print(" an empty eligible set (F5, with the fail-open trap firing as a control); and arms")
print(" at full margin under coverage k=N (FIX-ARM).")
print(" BOUNDARY: bounded per-N/per-k safety; unbounded liveness identity; DESIGN")
print(" combinatorics not Besu bytecode; the mainnet Falcon layer was log-only, not blocking,")
print(" until 2026-08-14 (blocking needs N>=7 + an ADDRESS-BOUND registry covering the set);")
print(" since then a validator refuses an anchor block whose certificate holds fewer valid seals than")
print(" the schedule requires (aere-node SPEC.md).")
print(" combinatorics not Besu bytecode; the mainnet per-block Falcon layer was log-only until block")
print(" 13,014,000 (2026-08-09), when the anchor rules were armed (blocking needs N>=7 + an ADDRESS-BOUND")
print(" registry covering the set): minimum 0 in the warm-up, then from block 13,034,000 a schedule step")
print(" to 3, held at an effective one by the emergency ceiling until 2026-08-14 (anchors of 2026-08-10 to")
print(" 2026-08-14 that carry fewer than three are named in the production client's two dated windows);")
print(" since 2026-08-14 a validator refuses an anchor block whose certificate holds fewer valid seals than")
print(" the schedule requires (aere-node SPEC.md; corrected 2026-10-27: this said log-only until 2026-08-14).")
else:
print(" NOT fully established (see FAILED / unexpected result above).")
import sys

View File

@ -346,7 +346,7 @@ if allok:
print(" {7,9,11} under <= f equivocating faults of each kind (H1); a block missing EITHER")
print(" quorum is REJECTED (H2a/H2b); and every hybrid-valid block is ECDSA-valid, so the")
print(" Falcon requirement can only SHRINK the committable set -> the hybrid chain is AT")
print(" LEAST AS SAFE as today's ECDSA-only chain, a Falcon bug can never make it worse")
print(" LEAST AS SAFE as the ECDSA-only chain of 2026-07-18, when this model was written; a Falcon bug can never make it worse")
print(" (H3, the core migration guarantee). The cost is liveness: hybrid needs 2f+1")
print(" validators good in BOTH dimensions; at f+1 combined-bad it can stall where")
print(" ECDSA-only would not (H4). N=7 has ZERO two-fault margin; N=9/N=11 restore margin.")

View File

@ -16,7 +16,8 @@
# chain-stopping validity rule; min() makes that inexpressible by construction,
# and this file machine-checks it.
#
# Chain facts modelled as LAW (chain 2800, live values):
# Chain facts modelled as LAW (chain 2800 as of 2026-08-15; corrected 2026-10-27: this line said 'live values'.
# Today the set has ten validators, since 2026-09-11, and the minimum is 7 per scheme since block 20,715,632):
# N = 9 validators, QBFT quorum = ceil(2N/3) = 6
# anchor heights: every 32 blocks from 13,014,000
# K schedule (height:K): 13,014,000 -> 0 ; 13,034,000 -> 3
@ -50,14 +51,14 @@ K_STEP_HEIGHT = 13_034_000 # schedule step: K goes 0 -> 3 here
K_WARMUP = 0 # schedule K on [13,014,000 .. 13,034,000)
K_ARMED = 3 # schedule K from 13,034,000 on
MAX_SEALS = 5 # write cap aere.pq.anchor.maxSeals
BLOCKING_FORK = 14_050_000 # no block finalizes without the Falcon quorum
BLOCKING_FORK = 14_050_000 # the withdrawn 'blocking fork' height (2026-08-19: it changed no enforcement); the FORK-* checks model the retired rule from here
REG1_HEIGHT, REG1_KEYS = 13_014_000, 7 # registry window 1
REG2_HEIGHT, REG2_KEYS = 13_600_000, 9 # registry window 2 (rotation)
N_VALIDATORS = 9
QBFT_QUORUM = 6 # ceil(2*9/3)
def k_schedule(h):
"""Height-indexed schedule 13014000:0, 13034000:3 (the live orar)."""
"""Height-indexed schedule 13014000:0, 13034000:3 (the schedule of 2026-08-15; the published one has 14961456:6, 17102384:0, 17102416:6 and 20715632:7 too)."""
return If(h >= K_STEP_HEIGHT, K_ARMED, K_WARMUP)
def k_eff(h, ceil_set, ceiling):
@ -97,7 +98,10 @@ def check(name, s, expect_unsat=True, kind="PROOF"):
return ok
print("### AERE PQ anchor -- CEILING MONOTONICITY: minSealsCeiling can only LOWER K_eff,")
print("### and K_eff <= maxSeals at every height (a conforming producer always suffices)\n")
print("### and K_eff <= maxSeals at every height (a conforming producer always suffices)")
print("### Chain of 2026-08-15: N=9, K schedule 13014000:0, 13034000:3, registries of 7 then 9 keys. The FORK-* rows")
print("### model the per-block rule withdrawn on 2026-08-19 at 14,050,000, which changed no enforcement (dated")
print("### 2026-10-27; today: ten validators, minimum 7 per scheme since block 20,715,632).\n")
# ---- CONFIG sanity: the quorum arithmetic and the height lattice are coherent -
s = Solver()
@ -115,7 +119,7 @@ check(f"CONFIG K-step height {K_STEP_HEIGHT:,} lands ON the 32-block anchor latt
s = Solver()
s.add(Int('ok') == (1 if (BLOCKING_FORK - ANCHOR_START) % ANCHOR_STEP == 0 else 0))
s.add(Int('ok') == 1)
check(f"CONFIG blocking fork {BLOCKING_FORK:,} lands ON the 32-block anchor lattice", s,
check(f"CONFIG the withdrawn fork height {BLOCKING_FORK:,} lands ON the 32-block anchor lattice", s,
expect_unsat=False, kind="CONFIG")
# =============================================================================
@ -223,7 +227,7 @@ h, ceiling, ceil_set = Int('h'), Int('ceiling'), Bool('ceil_set')
s.add(is_anchor_height(h), h >= BLOCKING_FORK, ceiling >= 0)
keff = k_eff(h, ceil_set, ceiling)
s.add(Or(keff > MAX_SEALS, keff > reg_keys(h))) # negate: unsatisfiable threshold
check(f"FORK-1 blocking era (h >= {BLOCKING_FORK:,}): NO ceiling makes the anchor "
check(f"FORK-1 modelled range (h >= {BLOCKING_FORK:,}): NO ceiling makes the anchor "
"threshold unsatisfiable (K_eff <= maxSeals AND K_eff <= registry keys)", s)
# ============================ NEGATIVE CONTROLS ==============================
@ -248,7 +252,7 @@ s = Solver()
h, ceiling = Int('h'), Int('ceiling')
s.add(is_anchor_height(h), h >= BLOCKING_FORK, ceiling >= 0)
s.add(k_eff_buggy_max(h, True, ceiling) > MAX_SEALS)
check(f"NEG-CTRL 2 PLANTED max() ceiling, blocking era: K_eff CAN exceed "
check(f"NEG-CTRL 2 PLANTED max() ceiling, h >= {BLOCKING_FORK:,}: K_eff CAN exceed "
f"maxSeals={MAX_SEALS} (a settable value becomes a chain-stop switch)", s,
expect_unsat=False, kind="NEG-CTRL")
@ -292,11 +296,11 @@ if allok:
print(" threshold -- K_eff = min(K_schedule, ceiling), K_eff <= K_schedule for every")
print(" height and every ceiling (a raising case is UNSAT, i.e. inexpressible), a")
print(" ceiling at/above the schedule is a no-op, and K_eff <= maxSeals=5 and")
print(" K_eff <= registry keys (7 then 9) at every height including the blocking era")
print(" from 14,050,000 -- so a conforming producer (heard >= K_eff) always writes")
print(" K_eff <= registry keys (7 then 9, the registries of 2026-08-15) at every height,")
print(" 14,050,000 and above included -- so a conforming producer (heard >= K_eff) always writes")
print(" min(heard, maxSeals) >= K_eff and the valve can never become a halt switch.")
print(" Negative controls FIRE: the planted max() variant raises K_eff (SAT), pushes")
print(" it past the write cap in the blocking era (SAT, a chain-stop), a planted")
print(" it past the write cap at h >= 14,050,000 (SAT, a chain-stop), a planted")
print(" under-cap without the loader guard yields only rejected certificates (SAT,")
print(" why AERE-PQC-ANCHOR-CONF-01 exists), and the valve itself is non-vacuous (SAT).")
print(" BOUNDARY: design arithmetic of the threshold pipeline, not Besu bytecode;")

View File

@ -66,7 +66,7 @@ ANCHOR_STEP = 32
K_STEP_HEIGHT = 13_034_000 # K schedule: 13014000:0, 13034000:3
K_MIN_SEALS = 3
MAX_SEALS = 5 # write cap
FORK_BLOCKING = 14_050_000 # no finality without the Falcon quorum from here
FORK_BLOCKING = 14_050_000 # the withdrawn 'blocking fork' height (2026-08-19: it changed no enforcement), kept as a modelled bound
REG1_HEIGHT = 13_014_000
REG1_KEYS = 7
REG2_HEIGHT = 13_600_000
@ -123,7 +123,9 @@ def check(name, s, expect_unsat=True, kind="PROOF"):
return ok
print("### AERE PQ anchor -- REGISTRY ROTATION COVERAGE"
" (R1@13,014,000 x7 keys, R2@13,600,000 x9 keys)\n")
" (R1@13,014,000 x7 keys, R2@13,600,000 x9 keys: the registries of 2026-08-15)")
print("### (dated 2026-10-27: later epochs, ten keys from 2026-09-11 and post-quantum ids from block 20,836,228, are not")
print("### modelled here; 14,050,000 below is the withdrawn 'blocking fork' height, which changed no enforcement)\n")
# =============================================================================
# C1a NO GAP: every anchor height >= 13,014,000 has at least one registry
@ -178,7 +180,7 @@ check("boundary: K-step height 13,034,000 IS anchor-aligned "
s = Solver()
k, r = Int('k'), Int('r')
s.add(FORK_BLOCKING == ANCHOR0 + ANCHOR_STEP * k + r, r >= 1, r <= 31)
check("boundary: blocking fork 14,050,000 IS anchor-aligned "
check("boundary: the withdrawn fork height 14,050,000 IS anchor-aligned "
"(remainder 1..31 is infeasible)", s)
# =============================================================================
@ -223,7 +225,7 @@ h = Int('h')
add_anchor(s, h, 'k')
s.add(h >= FORK_BLOCKING)
s.add(Or(Not(active_r2(h)), active_r1(h))) # negate: not-R2 or still-R1
check("blocking era: every anchor >= 14,050,000 is covered by the 9-key R2 "
check("modelled range: every anchor >= 14,050,000 is covered by the 9-key R2 "
"and only by it", s)
# the active registry at any blocking-era anchor can supply the Falcon quorum
@ -232,8 +234,8 @@ h = Int('h')
add_anchor(s, h, 'k')
s.add(h >= FORK_BLOCKING)
s.add(reg_size(lookup(h)) < QBFT_QUORUM) # negate: registry too small
check("blocking era: active registry size (9) >= Falcon quorum (6) at every "
"blocking-era anchor", s)
check("modelled range: active registry size (9) >= Falcon quorum (6) at every "
"anchor >= 14,050,000", s)
# minSealsCeiling only LOWERS K; effective K never exceeds K=3, the write cap
# maxSeals=5, or the size of the registry active at any covered anchor
@ -308,9 +310,9 @@ if allok:
print(" active-until-next semantics) covers every anchor height >= 13,014,000")
print(" with EXACTLY one registry, unbounded in height: no gap, no overlap.")
print(" The rotation boundary 13,600,000 is not anchor-aligned and interval")
print(" coverage loses no anchor; the K-step and blocking-fork heights are")
print(" coverage loses no anchor; the K-step height and the withdrawn fork height are")
print(" anchor-aligned. Anchor-keyed validation is replay-stable and rejects")
print(" R2-only keys on R1-era anchors; the blocking era >= 14,050,000 is")
print(" R2-only keys on R1-era anchors; with the registries of 2026-08-15, every anchor >= 14,050,000 is")
print(" served entirely by the 9-key registry, which always covers the Falcon")
print(" quorum (6) and the effective K (<= 3 <= maxSeals 5). All four negative")
print(" controls FIRE: a gapped schedule orphans an anchor, a forgotten")

View File

@ -27,7 +27,7 @@ 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"),
("Anchor THRESHOLD safety (K=3 of 9 on anchor blocks since 2026-08-14, registry rotation)", "anchor_blocking_quorum_smt.py"),
("Anchor THRESHOLD safety (the chain of 2026-08-15: K=3 of 9 on anchor blocks, registry rotation; 7 of 10 since block 20,715,632)", "anchor_blocking_quorum_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"),