diff --git a/verification/Proofs/AxiomCheck.lean b/verification/Proofs/AxiomCheck.lean index 3d27b90..b587815 100644 --- a/verification/Proofs/AxiomCheck.lean +++ b/verification/Proofs/AxiomCheck.lean @@ -6,6 +6,7 @@ import Proofs.Descent import Proofs.Consistency import Proofs.Binding3 import Proofs.Refactor +import Proofs.Theorem3 #print axioms LTLAcc.domsep #print axioms LTLAcc.kbelow_pos #print axioms LTLAcc.kbelow_lt @@ -32,3 +33,6 @@ import Proofs.Refactor #print axioms LTLAcc.consRecBinding #print axioms LTLAcc.consRec_base_false_eq #print axioms LTLAcc.consRec_base_true_eq +#print axioms LTLAcc.extractCons +#print axioms LTLAcc.extractCons_correct +#print axioms LTLAcc.extractCons_nonvacuous diff --git a/verification/Proofs/AxiomCheck.olean b/verification/Proofs/AxiomCheck.olean index f2afdfa..08b26f1 100644 Binary files a/verification/Proofs/AxiomCheck.olean and b/verification/Proofs/AxiomCheck.olean differ diff --git a/verification/Proofs/Theorem3.lean b/verification/Proofs/Theorem3.lean new file mode 100644 index 0000000..61d78ac --- /dev/null +++ b/verification/Proofs/Theorem3.lean @@ -0,0 +1,67 @@ +/- S5.4 — **Theorem 3 (Consistency soundness)**, assembled: the explicit + extractor š“”ā€² for history rewrites. Joins consRecBinding (steps 1-2, + S5.3) to extractMTH (step 3, S4). + + Statement design per the corpus discipline: a NAMED function whose + correctness is about ITS OUTPUT (pigeonhole/choice cannot discharge + it), guarded by a permanent non-vacuity witness. -/ +import Proofs.Binding3 + +namespace LTLAcc + +/-- The consistency extractor š“”ā€² (paper Theorem 3). On a claimed rewrite + — an accepted consistency proof `C` between the pinned root of `Dā‚€` + and the head of `D₁`, where `Dā‚€` is NOT the real prefix — return the + node collision found while walking the fold, or descend into the two + same-root prefix trees. -/ +noncomputable def extractCons (nā‚€ : Nat) (C : List Hash) + (Dā‚€ D₁ : List Bytes) : List UInt8 Ɨ List UInt8 := + match extractConsNode nā‚€ D₁.length C true (MTH Dā‚€) D₁ with + | some c => c + | none => extractMTH Dā‚€ (D₁.take nā‚€) + +/-- **Theorem 3 (Consistency soundness), explicit form**: if the + consumer's verifier accepts `C` between the pinned head `MTH Dā‚€` + (size `nā‚€`) and the offered head `MTH D₁`, but `Dā‚€` is not the real + prefix of `D₁`, then `extractCons` outputs a genuine SHA-256 + collision. -/ +theorem extractCons_correct (nā‚€ : Nat) (C : List Hash) (Dā‚€ D₁ : List Bytes) + (hlen0 : Dā‚€.length = nā‚€) (hn0 : 0 < nā‚€) (hle : nā‚€ ≤ D₁.length) + (hne : Dā‚€ ≠ D₁.take nā‚€) + (hacc : ConsRec nā‚€ D₁.length C true (MTH Dā‚€) = some (MTH Dā‚€, MTH D₁)) : + IsCollision (extractCons nā‚€ C Dā‚€ D₁).1 (extractCons nā‚€ C Dā‚€ D₁).2 := by + have hbind := consRecBinding (MTH Dā‚€) nā‚€ D₁.length C true D₁ + (MTH Dā‚€) (MTH D₁) rfl hn0 hle hacc rfl + rw [extractCons] + cases hrec : extractConsNode nā‚€ D₁.length C true (MTH Dā‚€) D₁ with + | some c => + rw [hrec] at hbind + exact hbind + | none => + rw [hrec] at hbind + -- hbind : MTH Dā‚€ = MTH (D₁.take nā‚€); descend + have htklen : (D₁.take nā‚€).length = nā‚€ := by + rw [List.length_take]; omega + exact extractMTH_correct Dā‚€ (D₁.take nā‚€) (by omega) hne hbind + +/-- Permanent non-vacuity witness: on a NON-rewrite input (the pinned + list IS the real prefix), the extractor's output is provably NOT a + collision — so the correctness conclusion is false for some inputs + and cannot be discharged by pigeonhole or choice. Uses the honest + nā‚€ = n base: Dā‚€ = D₁ = [[7]], C = [], where ConsRec accepts and + extractConsNode returns none, so extractCons = extractMTH Dā‚€ Dā‚€ = + the equal leaf pair. -/ +theorem extractCons_nonvacuous : + ¬ IsCollision (extractCons 1 [] [([7] : List UInt8)] [([7] : List UInt8)]).1 + (extractCons 1 [] [([7] : List UInt8)] [([7] : List UInt8)]).2 := by + rw [extractCons] + have hrec : extractConsNode 1 ([([7] : List UInt8)]).length [] true + (MTH [([7] : List UInt8)]) [([7] : List UInt8)] = none := by + rw [extractConsNode]; simp + rw [hrec] + rw [extractMTH] + simp only [List.length_singleton, if_pos (by omega : (1:Nat) ≤ 1)] + intro hcol + exact hcol.1 rfl + +end LTLAcc diff --git a/verification/Proofs/Theorem3.olean b/verification/Proofs/Theorem3.olean new file mode 100644 index 0000000..01527c4 Binary files /dev/null and b/verification/Proofs/Theorem3.olean differ diff --git a/verification/check.sh b/verification/check.sh index 6654bd4..06f318e 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 Consistency Binding3 Refactor ) +PROOFS=( Basic Completeness Extract Descent Consistency Binding3 Refactor Theorem3 ) # Certificates and their exact expected cones (observed at first green # compile, 2026-07-10; any drift in EITHER direction is a failure). @@ -48,6 +48,9 @@ declare -A CONES=( [LTLAcc.consRecBinding]="propext, Classical.choice, LTLAcc.sha256, Quot.sound" [LTLAcc.consRec_base_false_eq]="propext, Quot.sound" [LTLAcc.consRec_base_true_eq]="propext, Quot.sound" + [LTLAcc.extractCons]="propext, LTLAcc.sha256, Quot.sound" + [LTLAcc.extractCons_correct]="propext, Classical.choice, LTLAcc.sha256, Quot.sound" + [LTLAcc.extractCons_nonvacuous]="propext, LTLAcc.sha256, Quot.sound" ) free -m | awk '/Mem:/{if($7<2048){print "FATAL: <2GB RAM available — refusing to compile"; exit 1}}'