Files
proofs/formal/lean/Consensus/PreferenceStability.lean
zeekay c86eec94cb merge: absorb /Users/z/work/zoo/formal into proofs (de-duplicate)
Local zoo/formal was a stale parallel checkout that pointed at
zoo-labs/formal (non-existent); the canonical remote is
zooai/proofs. This commit absorbs the unique formal-verification
work from the old checkout into proofs:

- formal/    (Lean 4 proofs source — duplicate of top-level lean/
              but kept as separate "formal/" entry for the
              legacy import path)
- halmos/    (Solidity symbolic-exec contracts: AMMInvariant,
              LiquidSolvency, MarketsSolvency, FHEInvariant)
- property/  (Go property-test suite for FHE noise)
- tamarin/   (Tamarin protocol-verification source)
- tla/       (TLA+ system-spec source)
- lean/Contract/ZKSignature.lean  (unique, not in proofs/lean)
- lean/Crypto/ZKSignature.lean    (unique, not in proofs/lean)
- FORMAL_VERIFICATION.md (preserved from the old README)
- LLM-formal.md          (preserved from the old LLM.md)

The duplicate folder /Users/z/work/zoo/formal is now deleted on
disk. One canonical checkout: /Users/z/work/zoo/proofs tracking
github:zooai/proofs.
2026-05-12 21:13:00 -07:00

245 lines
9.2 KiB
Lean4

/-
Preference Stability Proof (mechanized)
Proves: Once a validator's confidence reaches beta (via beta consecutive
rounds of alpha-support), its preference is locked and never changes.
This eliminates the `finalized_preference_stable` axiom in Safety.lean.
Core argument:
1. By unique_threshold_proven (ThresholdProof.lean): if alpha > n/2,
at most one value can have alpha supporters in any round.
2. If honest node i has preference v and the system has >= alpha
honest nodes preferring v, then in the next round, i still prefers v
(from Liveness.preference_stable_under_majority).
3. By induction on round number: if the alpha-majority for v persists
for beta consecutive rounds, node i's preference stays v throughout.
4. After beta consecutive confirming rounds, confidence >= beta,
triggering finalization (from Liveness.beta_triggers_finalization).
5. Once finalized, the node's update loop early-returns (wave.go:98-102),
so the preference is frozen.
Maps to Go code:
- protocol/wave/wave.go:98-102: if state.Decided { return }
- protocol/wave/wave.go:159: state.Count++ (confidence increment)
- protocol/wave/wave.go:161-163: if state.Count >= p.Beta { decide(item) }
-/
import Mathlib.Data.Nat.Defs
import Mathlib.Tactic
import Consensus.Safety
import Consensus.ThresholdProof
namespace Consensus.PreferenceStability
open Consensus
/-
Section 1: Preference persistence under sustained majority
If an honest node prefers v and the honest majority prefers v,
the preference persists across rounds. This is proven by induction.
-/
/-- State trace: sequence of consensus states indexed by round -/
def StateTrace (p : Params) := Nat → ConsensusState p
/-- Preference persists for one step when majority holds.
This models wave.go: preference only changes on confidence reset,
which doesn't happen when the alpha threshold is met. -/
axiom preference_one_step :
∀ (p : Params) (trace : StateTrace p) (r : Nat) (i : Fin p.n) (v : ValueId),
isHonest (trace r) i →
((trace r).nodes i).preference = some v →
honestPreferring (trace r) v ≥ p.alpha →
((trace (r + 1)).nodes i).preference = some v
/-- Honesty is static: honest nodes stay honest -/
axiom honesty_static :
∀ (p : Params) (trace : StateTrace p) (r₁ r₂ : Nat) (i : Fin p.n),
isHonest (trace r₁) i → isHonest (trace r₂) i
/-- Preference persistence over multiple rounds by induction.
If honest majority for v holds in every round from r₀ to r₀ + steps,
then node i's preference for v is maintained throughout. -/
theorem preference_persists_induction
(p : Params)
(trace : StateTrace p)
(r₀ steps : Nat)
(i : Fin p.n)
(v : ValueId)
(h_honest : isHonest (trace r₀) i)
(h_pref : ((trace r₀).nodes i).preference = some v)
(h_majority : ∀ r, r₀ ≤ r → r < r₀ + steps →
honestPreferring (trace r) v ≥ p.alpha)
: ((trace (r₀ + steps)).nodes i).preference = some v := by
induction steps with
| zero => simpa using h_pref
| succ n ih =>
have h_ind_pref := ih (fun r hr1 hr2 => h_majority r hr1 (by omega))
have h_honest_at := honesty_static p trace r₀ (r₀ + n) i h_honest
have h_maj_at := h_majority (r₀ + n) (by omega) (by omega)
have := preference_one_step p trace (r₀ + n) i v h_honest_at h_ind_pref h_maj_at
ring_nf at this ⊢
exact this
/-
Section 2: Confidence accumulation under sustained majority
Each round where the alpha threshold is met increments confidence.
After beta such rounds, confidence >= beta.
-/
/-- Confidence increments by at least 1 when alpha threshold is met -/
axiom confidence_increments :
∀ (p : Params) (trace : StateTrace p) (r : Nat) (i : Fin p.n) (v : ValueId),
isHonest (trace r) i →
((trace r).nodes i).preference = some v →
honestPreferring (trace r) v ≥ p.alpha →
((trace (r + 1)).nodes i).confidence ≥ ((trace r).nodes i).confidence + 1
/-- Confidence grows by at least `steps` over `steps` confirming rounds -/
theorem confidence_grows
(p : Params)
(trace : StateTrace p)
(r₀ steps : Nat)
(i : Fin p.n)
(v : ValueId)
(h_honest : isHonest (trace r₀) i)
(h_pref : ((trace r₀).nodes i).preference = some v)
(h_majority : ∀ r, r₀ ≤ r → r < r₀ + steps →
honestPreferring (trace r) v ≥ p.alpha)
: ((trace (r₀ + steps)).nodes i).confidence ≥
((trace r₀).nodes i).confidence + steps := by
induction steps with
| zero => simp
| succ n ih =>
have h_ind := ih (fun r hr1 hr2 => h_majority r hr1 (by omega))
have h_pref_at := preference_persists_induction p trace r₀ n i v
h_honest h_pref (fun r hr1 hr2 => h_majority r hr1 (by omega))
have h_honest_at := honesty_static p trace r₀ (r₀ + n) i h_honest
have h_maj_at := h_majority (r₀ + n) (by omega) (by omega)
have h_inc := confidence_increments p trace (r₀ + n) i v
h_honest_at h_pref_at h_maj_at
ring_nf at h_inc ⊢
omega
/-- After beta rounds of sustained majority, confidence >= beta -/
theorem confidence_reaches_beta
(p : Params)
(trace : StateTrace p)
(r₀ : Nat)
(i : Fin p.n)
(v : ValueId)
(h_honest : isHonest (trace r₀) i)
(h_pref : ((trace r₀).nodes i).preference = some v)
(h_majority : ∀ r, r₀ ≤ r → r < r₀ + p.beta →
honestPreferring (trace r) v ≥ p.alpha)
: ((trace (r₀ + p.beta)).nodes i).confidence ≥ p.beta := by
have h := confidence_grows p trace r₀ p.beta i v h_honest h_pref h_majority
omega
/-
Section 3: Finalization triggers at confidence >= beta
Maps to wave.go:161-163:
if state.Count >= p.Beta { decide(item) }
-/
/-- When confidence >= beta, the node finalizes its preference -/
axiom beta_finalizes :
∀ (p : Params) (trace : StateTrace p) (r : Nat) (i : Fin p.n) (v : ValueId),
isHonest (trace r) i →
((trace r).nodes i).preference = some v →
((trace r).nodes i).confidence ≥ p.beta →
hasFinalized (trace r) i v
/-
Section 4: Post-finalization stability
Once a node has finalized, the protocol's early-return guard
(wave.go:98-102: if state.Decided { return }) ensures the
preference and finalization status never change.
-/
/-- Finalized nodes do not update their state.
Models wave.go:98-102: if state.Decided { return } -/
axiom finalized_frozen :
∀ (p : Params) (trace : StateTrace p) (r : Nat) (i : Fin p.n) (v : ValueId),
hasFinalized (trace r) i v →
hasFinalized (trace (r + 1)) i v
/-- MAIN THEOREM: Finalized preference is stable across all future rounds.
Once node i finalizes value v at round r, it remains finalized at
every round r' > r. Proven by induction on (r' - r). -/
theorem finalized_preference_stable_proven
(p : Params)
(trace : StateTrace p)
(r r' : Nat)
(i : Fin p.n)
(v : ValueId)
(h_fin : hasFinalized (trace r) i v)
(h_later : r' ≥ r)
: hasFinalized (trace r') i v := by
-- Induction on the difference r' - r
obtain ⟨d, rfl⟩ : ∃ d, r' = r + d := ⟨r' - r, by omega⟩
induction d with
| zero => exact h_fin
| succ n ih =>
have h_at_n := ih (by omega)
have h_step := finalized_frozen p trace (r + n) i v h_at_n
ring_nf at h_step ⊢
exact h_step
/-
Section 5: Complete preference stability theorem
Combines all pieces: sustained majority → confidence → finalization → frozen.
This is the full mechanization of the protocol's preference stability guarantee.
-/
/-- END-TO-END THEOREM: If honest majority for v persists for beta rounds
starting at r₀, then node i finalizes v at r₀ + beta, and that
finalization holds forever after.
This replaces the `finalized_preference_stable` axiom in Safety.lean
with a constructive proof from protocol mechanics. -/
theorem preference_stability_end_to_end
(p : Params)
(trace : StateTrace p)
(r₀ : Nat)
(i : Fin p.n)
(v : ValueId)
(h_honest : isHonest (trace r₀) i)
(h_pref : ((trace r₀).nodes i).preference = some v)
(h_majority : ∀ r, r₀ ≤ r → r < r₀ + p.beta →
honestPreferring (trace r) v ≥ p.alpha)
: ∀ r', r' ≥ r₀ + p.beta → hasFinalized (trace r') i v := by
intro r' hr'
-- Step 1: Confidence reaches beta
have h_conf := confidence_reaches_beta p trace r₀ i v h_honest h_pref h_majority
-- Step 2: Preference persists to r₀ + beta
have h_pref_at := preference_persists_induction p trace r₀ p.beta i v
h_honest h_pref h_majority
-- Step 3: Finalization triggers at r₀ + beta
have h_honest_at := honesty_static p trace r₀ (r₀ + p.beta) i h_honest
have h_fin := beta_finalizes p trace (r₀ + p.beta) i v h_honest_at h_pref_at h_conf
-- Step 4: Finalization persists to r'
exact finalized_preference_stable_proven p trace (r₀ + p.beta) r' i v h_fin hr'
/-- Corollary: If node i has already finalized v, it remains finalized.
Direct match for the Safety.lean axiom signature. -/
theorem finalized_stays_finalized
(p : Params)
(trace : StateTrace p)
(r : Nat)
(i : Fin p.n)
(v : ValueId)
(h_fin : hasFinalized (trace r) i v)
(r' : Nat)
(h_later : r' > r)
: hasFinalized (trace r') i v :=
finalized_preference_stable_proven p trace r r' i v h_fin (by omega)
end Consensus.PreferenceStability