mirror of
https://github.com/saymrwulf/ltl-accumulator-verified.git
synced 2026-09-03 19:53:48 +00:00
Round-3 verdicts: GPT-5.6 conditionally approves (blockers closed, one portability finding); the Claude reviewer's Socratic addendum produced F1*, the strongest finding of the series — deployed verify_consistency and mechanized ConsRec are NOT extensionally equal. Reproduced exactly (witness verify_consistency(1,3,R2,R3,P(2→3))=True vs ConsRec reject; 3,405 divergences n<60; strictly one-sided; power-of-two seeding mechanism confirmed in source). - KNOWN-GAPS gap 14: witness, mechanism, one-sidedness, and the pinned-pair side condition under which Theorem 3 transfers to the deployed verifier (pacta's pin-store flow supplies it by construction). No pacta code change; deployed behavior matches upstream RFC 9162 implementations. - fidelity: lied-size family — 73,573 boundary cases, 3,867 expected divergences PINNED, one-sided direction asserted per case. Banner rescoped: agreement over pinned families, not extensional equality. - Theorem3.lean: acceptCons_sound (F2) — soundness over the named acceptCons predicate, n₀=0 discharged from the non-prefix premise, size bound derived from acceptance via new consRec_some_le. Cones read from #print axioms; CONES/AxiomCheck/allowlist updated (218 → 222 constants, diff = the two theorems + two generated auxiliaries). - F3/GPT§7: verification/lean-toolchain pin + run_bare.sh (reviewer's standalone runner, plain public lean — verified green: 61 cones, 222 constants, gate green) + AENEAS_ENV override in check.sh and selftest_audit.sh. - F4: awk field-equality replaces regex-with-dots in Phase 3b. - F5: git-tracked .pyc removed (worse than reported — it was in the repo, not just the kit); __pycache__ gitignored; round-4 kit ships a corpus MANIFEST.sha256 + pinned commit (also GPT's governance condition). check.sh exit 0, ATTESTATION GREEN; selftest exit 0, 9/9 + control. Live LTL untouched (12 leaves, bcd15f9d…); attestation still gated on ePrint decision + author review + explicit operator order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
118 lines
5.9 KiB
Text
118 lines
5.9 KiB
Text
/- 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
|
||
|
||
/-- Theorem 3 at the paper's exact quantifiers (review M4): `n₀ ≤ n₁`
|
||
without a separate `0 < n₀`. The `n₀ = 0` case is discharged: `D₀`
|
||
has length 0 so `D₀ = [] = D₁.take 0`, contradicting `hne`. -/
|
||
theorem extractCons_correct_paper (n₀ : Nat) (C : List Hash) (D₀ D₁ : List Bytes)
|
||
(hlen0 : D₀.length = 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
|
||
rcases Nat.eq_zero_or_pos n₀ with h0 | hpos
|
||
· exfalso; apply hne
|
||
have hD0 : D₀ = [] := List.length_eq_zero_iff.mp (by omega)
|
||
rw [hD0, h0]; simp
|
||
· exact extractCons_correct n₀ C D₀ D₁ hlen0 hpos hle hne hacc
|
||
|
||
/-- `ConsRec` acceptance implies the size bound: the `n₀ > n` branch
|
||
returns `none`, so a `some` forces `n₀ ≤ n`. Lets `acceptCons_sound`
|
||
owe no separate range hypothesis (mirrors `acceptIncl_sound`
|
||
deriving `m < n` from `hacc.1` — review round 3, F2). -/
|
||
theorem consRec_some_le {n₀ n : Nat} {C : List Hash} {b : Bool} {r : Hash}
|
||
{p : Hash × Hash} (h : ConsRec n₀ n C b r = some p) : n₀ ≤ n := by
|
||
rcases Nat.lt_or_ge n n₀ with hgt | hge
|
||
· rw [ConsRec, if_neg (by omega : ¬ n₀ = n),
|
||
if_pos (Or.inl hgt : n₀ > n ∨ n₀ = 0 ∨ n ≤ 1)] at h
|
||
simp at h
|
||
· exact hge
|
||
|
||
/-- Consistency soundness through the named acceptance predicate
|
||
(review round 3, F2 — the consistency twin of `acceptIncl_sound`):
|
||
if `acceptCons` holds between the pinned head of `D₀` and the head
|
||
of `D₁` but `D₀` is not the real prefix, `extractCons` outputs a
|
||
collision. The `n₀ = 0` disjunct of `acceptCons` is impossible under
|
||
`hne` (`D₀ = [] = D₁.take 0`); the size bound comes from acceptance
|
||
itself (`consRec_some_le`).
|
||
|
||
SCOPE (gap 14): this covers the MECHANIZED accept predicate. The
|
||
deployed `verify_consistency` accepts strictly more on inputs whose
|
||
claimed sizes are not the authentic sizes of the trees behind the
|
||
roots; soundness transfers to deployment only under the pinned-pair
|
||
side condition documented in KNOWN-GAPS gap 14. -/
|
||
theorem acceptCons_sound (n₀ : Nat) (C : List Hash) (D₀ D₁ : List Bytes)
|
||
(hlen0 : D₀.length = n₀)
|
||
(hne : D₀ ≠ D₁.take n₀)
|
||
(hacc : acceptCons n₀ D₁.length (MTH D₀) (MTH D₁) C) :
|
||
IsCollision (extractCons n₀ C D₀ D₁).1 (extractCons n₀ C D₀ D₁).2 := by
|
||
rcases hacc with h0 | hcons
|
||
· exfalso; apply hne
|
||
have hD0 : D₀ = [] := List.length_eq_zero_iff.mp (by omega)
|
||
rw [hD0, h0]; simp
|
||
· exact extractCons_correct_paper n₀ C D₀ D₁ hlen0
|
||
(consRec_some_le hcons) hne hcons
|
||
|
||
end LTLAcc
|