diff --git a/README.md b/README.md index 7a32906..f808711 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ the same discipline as the four `*-ed25519-verified` subject corpora. | L5 | inclusion soundness = EXPLICIT extractor `extractIncl` (Theorem 2) **done, non-vacuous** | | L6a | descent extractor `extractMTH` (Theorem 3 step 3 = Lemma 2, WHOLE-TREE instance) **done, non-vacuous** | | — | Lemma 2, PATH instance (receipt-uniqueness of `Root`): deleted with the vacuous `root_binding` in S3.5 and **not yet restored**; optional, not needed for Theorem 3 | -| L6b | ConsRec binding + Theorem 3 assembly (extractCons) | pending (S5) | +| L6b | ConsRec binding + Theorem 3 assembly (extractCons) | in progress (S5): stage-1 arithmetic/list infrastructure done (kbelow_prefix_eq, take surgery); binding + assembly next | | L6 | pin-store state machine safety (Proposition 1) | pending | ## Discipline (identical to the subject corpora) diff --git a/verification/Proofs/AxiomCheck.lean b/verification/Proofs/AxiomCheck.lean index 8c12f5e..202c3fa 100644 --- a/verification/Proofs/AxiomCheck.lean +++ b/verification/Proofs/AxiomCheck.lean @@ -3,6 +3,7 @@ import Proofs.Basic import Proofs.Completeness import Proofs.Extract import Proofs.Descent +import Proofs.Consistency #print axioms LTLAcc.domsep #print axioms LTLAcc.kbelow_pos #print axioms LTLAcc.kbelow_lt @@ -21,3 +22,6 @@ import Proofs.Descent #print axioms LTLAcc.extractMTH #print axioms LTLAcc.extractMTH_correct #print axioms LTLAcc.extractMTH_nonvacuous +#print axioms LTLAcc.kbelow_prefix_eq +#print axioms LTLAcc.take_take_le +#print axioms LTLAcc.take_drop_prefix diff --git a/verification/Proofs/AxiomCheck.olean b/verification/Proofs/AxiomCheck.olean index 4e32568..1952ad9 100644 Binary files a/verification/Proofs/AxiomCheck.olean and b/verification/Proofs/AxiomCheck.olean differ diff --git a/verification/Proofs/Consistency.lean b/verification/Proofs/Consistency.lean new file mode 100644 index 0000000..c91af52 --- /dev/null +++ b/verification/Proofs/Consistency.lean @@ -0,0 +1,67 @@ +/- S5 (stage 1) — infrastructure for consistency soundness (paper Theorem 3, + steps 1-2). The binding argument needs one non-obvious arithmetic fact and + two list-surgery facts, isolated and proven here before the main proof. + + Arithmetic: when the pinned prefix of size n₀ spills past the left subtree + (k < n₀ ≤ n, k = kbelow n), the honest tree of `D₁.take n₀` splits at the + SAME point k. That is `kbelow n₀ = k`, and it holds because k is a power of + two with k < n₀ ≤ 2k, which pins kbelow uniquely. -/ +import Proofs.Descent + +namespace LTLAcc + +/-- Two powers of two both lying in `(m/2, m]` (i.e. `2^a < m ≤ 2^(a+1)`) + have the same exponent. -/ +theorem pow2_exp_unique {a j m : Nat} + (ha : 2^a < m) (ha2 : m ≤ 2^(a+1)) (hj : 2^j < m) (hj2 : m ≤ 2^(j+1)) : + a = j := by + rcases Nat.lt_trichotomy a j with h | h | h + · -- a < j ⇒ a+1 ≤ j ⇒ 2^(a+1) ≤ 2^j < m, contradicting m ≤ 2^(a+1) + have : a + 1 ≤ j := h + have hle : 2^(a+1) ≤ 2^j := Nat.pow_le_pow_right (by omega) this + omega + · exact h + · have : j + 1 ≤ a := h + have hle : 2^(j+1) ≤ 2^a := Nat.pow_le_pow_right (by omega) this + omega + +/-- `kbelow` is pinned by its defining inequalities: a power of two `p` + with `p < m ≤ 2p` IS `kbelow m`. -/ +theorem kbelow_eq_of_pow2_between {p m : Nat} (j : Nat) (hp : p = 2^j) + (h1 : p < m) (h2 : m ≤ 2 * p) : kbelow m = p := by + have hm2 : 2 ≤ m := by + have : 1 ≤ p := by rw [hp]; exact Nat.one_le_two_pow + omega + obtain ⟨a, ha⟩ := kbelow_pow2 m + have hlt := kbelow_lt m hm2 + have hle := le_two_kbelow m hm2 + -- kbelow m = 2^a with 2^a < m ≤ 2^(a+1); p = 2^j with 2^j < m ≤ 2^(j+1) + rw [ha] at hlt hle + have hj2 : m ≤ 2^(j+1) := by rw [Nat.pow_succ]; omega + have ha2 : m ≤ 2^(a+1) := by rw [Nat.pow_succ]; omega + have hja : 2^j < m := by omega + have : a = j := pow2_exp_unique hlt ha2 hja hj2 + rw [ha, this, ← hp] + +/-- The specialization used in the binding: with `k = kbelow n`, `2 ≤ n`, + and `k < n₀ ≤ n`, the prefix tree splits at the same `k`. -/ +theorem kbelow_prefix_eq {n n₀ : Nat} (hn : 2 ≤ n) + (hk : k = kbelow n) (hlo : k < n₀) (hhi : n₀ ≤ n) : + kbelow n₀ = k := by + obtain ⟨j, hj⟩ := kbelow_pow2 n + rw [← hk] at hj + have hle := le_two_kbelow n hn + rw [← hk] at hle + exact kbelow_eq_of_pow2_between j hj hlo (by omega) + +/-! ### list surgery -/ + +theorem take_take_le (l : List Bytes) (k n₀ : Nat) (h : k ≤ n₀) : + (l.take n₀).take k = l.take k := by + rw [List.take_take]; congr 1; omega + +theorem take_drop_prefix (l : List Bytes) (k n₀ : Nat) : + (l.take n₀).drop k = (l.drop k).take (n₀ - k) := by + rw [List.drop_take] + +end LTLAcc diff --git a/verification/Proofs/Consistency.olean b/verification/Proofs/Consistency.olean new file mode 100644 index 0000000..50cc899 Binary files /dev/null and b/verification/Proofs/Consistency.olean differ diff --git a/verification/check.sh b/verification/check.sh index 2616687..d09cb4a 100755 --- a/verification/check.sh +++ b/verification/check.sh @@ -17,7 +17,7 @@ export LEAN_MEM_MB="${LEAN_MEM_MB:-4096}" CORES="${LEAN_MAX_CORES:-0-3}" GEN_MODULES=( LTLAcc/HashExternal ) -PROOFS=( Basic Completeness Extract Descent ) +PROOFS=( Basic Completeness Extract Descent Consistency ) # Certificates and their exact expected cones (observed at first green # compile, 2026-07-10; any drift in EITHER direction is a failure). @@ -40,6 +40,9 @@ declare -A CONES=( [LTLAcc.extractMTH]="propext, LTLAcc.sha256, Quot.sound" [LTLAcc.extractMTH_correct]="propext, Classical.choice, LTLAcc.sha256, Quot.sound" [LTLAcc.extractMTH_nonvacuous]="propext, LTLAcc.sha256, Quot.sound" + [LTLAcc.kbelow_prefix_eq]="propext, Quot.sound" + [LTLAcc.take_take_le]="propext, Quot.sound" + [LTLAcc.take_drop_prefix]="propext, Classical.choice, Quot.sound" ) free -m | awk '/Mem:/{if($7<2048){print "FATAL: <2GB RAM available — refusing to compile"; exit 1}}'