Veil Framework

repository·main·Indexed 42 days ago

https://github.com/verse-lab/veil

A foundational framework embedded in the Lean 4 proof assistant for specifying, implementing, testing, and proving safety properties of state transition systems, specifically targeting distributed protocols. It provides a DSL for defining modules, actions, and invariants, with support for SMT-based verification via #check_invariants, explicit-state model checking, and symbolic bounded model checking.

Tokens
3.7K
Snippets
14
Records
20
Agent score
56%

What's inside Veil

  1. Understand the Stellar Consensus Protocol (SCP) formalization in Veil

    main

    This example demonstrates the formalization and verification of the Stellar Consensus Protocol (SCP) within the Veil framework. The implementation is adapted from the original SCP proofs (originally in Ivy and Isabelle/HOL) and provides two layers of modeling:

    1. Concrete System Model: A higher-order model where concepts like quorums have explicit definitions involving sets and quantifications.
    2. Abstract Model: A first-order logic abstraction where system properties (e.g., node_properties and quorum_properties) are stated as axioms.

    The verification goal is to prove that the concrete model satisfies the abstract model's properties.

  2. Define actions, procedures, and transitions

    main

    Veil provides three ways to specify transitions:

    1. Actions: Externally visible, atomic transitions. If an assertion fails, all changes are discarded. Use require for preconditions.
    2. Procedures: Internal helper routines called by actions or other procedures. They are not visible to the environment.
    3. Two-State Transitions: Defined via the transition keyword as a relational mapping between a pre-state and a post-state (accessed via primed variables like is_byz'). This is useful for modeling environment behaviors like Byzantine adversaries.
    action send (n next : node) {
      require ∀ Z, n ≠ next ∧ ((Z ≠ n ∧ Z ≠ next) → btw n next Z)
      pending n next := true
    }
    
    procedure sendToNext (payload src : node) {
      let msg := Message.mk payload src (nextNode src)
      if msg ∉ messages then
        messages := msg :: messages
    }
    
    transition byz {
      ∀ (src dst : node) (r : round) (v : value),
        (¬ is_byz src ∧ (initial_msg src dst r v ↔ initial_msg' src dst r v)) ∨
        (is_byz src ∧ (initial_msg src dst r v → initial_msg' src dst r v))
    }
  3. Define state and theory components

    main

    The signature of a transition system is defined by three types of components. Components can be mutable (default) or immutable (part of the background theory).

    • Individuals: Single values of a type. Use immutable for constants.
    • Relations: Predicates over types. Important: Declare relations as Bool-valued (not Prop-valued) to ensure the state is executable for the model checker.
    • Functions: Total functions from domain to codomain. Use immutable for fixed mappings like topology.
    individual leader : List node           -- mutable
    immutable individual maxRound : round   -- immutable
    
    relation leader : node -> Bool          -- mutable relation
    
    function currentRound : node -> Nat    -- function
    immutable function nextNode : node -> node
  4. Veil specification file conventions

    main

    When writing your own Veil specifications, follow these project conventions:

    • Naming: Use PascalCase for file names (e.g., TwoPhaseCommit.lean).
    • Module Declaration: Each file must declare a veil module that matches the file name.
    • Imports: Each file should import only Veil.
  5. Navigate the Stellar Consensus Protocol example files

    main

    The SCP example is organized into two primary Lean files:

    • SCPTheory.lean: Contains the concrete system model. This file is adapted from the Isabelle/HOL specification and defines the detailed mechanics of the protocol.
    • SCP.lean: Contains the abstract model (adapted from the Ivy specification) and the bridge proof. It includes the proof showing that the concrete model satisfies the abstract properties defined in the first-order logic abstraction.
  6. Declare a Veil module

    main

    A Veil module defines a state transition system, including its background theory and state. Every module must start with import Veil, begin with veil module <Name>, and end with end <Name>.

    import Veil
    
    veil module Ring
    -- module contents go here
    end Ring
  7. Explore Veil examples by category

    main

    Veil provides a variety of protocol specifications organized by their source or modeling style. Use these to learn different modeling patterns:

    • Tutorials: Best for beginners. Includes Ring.lean (syntax and commands) and FloodSet.lean (full multi-modal workflow: modeling $\rightarrow$ testing $\rightarrow$ interactive proof). The POPL26/ subfolder demonstrates different type encodings (decidable, finite, natural numbers).
    • Ivy: Uses Ivy-style first-order encodings with uninterpreted types and relations.
    • TLA: Translations of TLA+ specifications using concrete types, structures, and lists.
    • Synchronous: Models synchronous consensus protocols with time-bounded rounds and crash-fault tolerance.
    • Puzzles: State machine models of recreational puzzles, useful for practicing with the Veil model checker.
  8. Install and build Veil

    main

    Veil requires Lean 4, NodeJS, and Clang (for Lean CVC5). Follow these steps to set up the environment on Linux or MacOS:

    1. Install dependencies: Use the provided script to install system packages (curl, git, clang, etc.), nvm for Node.js, and elan for Lean 4.
    2. Clone the repository.
    3. Build the project: Use lake to fetch mathlib cache and build the binaries.

    Note: lake exe cache get is required to download a pre-built version of mathlib to avoid extremely long build times.

    # 1. Install dependencies (Linux/MacOS)
    set -o pipefail &&
    sudo apt-get update &&
    sudo apt-get install -y --no-install-recommends \
      ca-certificates curl git unzip clang lld libc++-dev libc++abi-dev &&
    (curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.7/install.sh | bash) &&
    . "$HOME/.nvm/nvm.sh" &&
    nvm install 24 &&
    (curl -fsSL https://leanprover.github.io/elan/elan-init.sh | sh -s -- -y --default-toolchain none) &&
    . "$HOME/.elan/env"
    
    # 2. Clone Veil
    git clone https://github.com/verse-lab/veil.git
    
    # 3. Build
    cd veil
    lake exe cache get
    lake build
  9. Perform explicit-state model checking

    main

    Use #model_check to exhaustively enumerate reachable states in a finite instance. The first argument instantiates parameters (types/params), and the second provides concrete values for the theory (immutable components).

    For non-exhaustive testing, use #simulate to perform random walks on the state graph.

    // Exhaustive model checking
    #model_check { node := Fin 4 } { nextNode := fun n => n + 1 }
    
    // Random simulation
    #simulate { node := Fin 3 } {} (numTraces := 2000) (maxSteps := 500) (seed := 42)
  10. Use Symbolic Bounded Model Checking

    main

    Symbolic Bounded Model Checking explores behaviors up to a bounded number of steps using SMT. It checks all instantiations of parameters at once.

    • sat trace: Finds an execution reaching a specific state or satisfying an assertion. Use an empty trace sat trace { } to check if assumptions are satisfiable.
    • unsat trace: Proves that no execution of a given shape reaches a specific state.
    // Find a satisfiable trace
    sat trace { 
      any 3 actions
      assert (∃ l, leader l)
    }
    
    // Prove an unsatisfiable trace
    unsat trace { 
      any 5 actions
      assert (∃ n₁ n₂, n₁ ≠ n₂ ∧ leader n₁ ∧ leader n₂)
    }
  11. Learn Veil via tutorials

    main

    You can learn the Veil DSL and its verification workflows through two primary walkthrough specifications located in the Examples/Tutorial directory:

    • Ring Leader Election (Ring.lean): Introduces Veil's syntax and core commands like #check_invariants, #model_check, and handling sat/unsat trace results.
    • FloodSet Protocol (FloodSet.lean): A complete multi-modal workflow covering modeling, testing via concrete and symbolic model checking, counterexample-driven invariant discovery, and interactive Lean proofs.

    These examples are also available in the online playground under the Examples button.

  12. Build and check Veil examples using Lake

    main

    Veil examples are managed using lake. You can build the entire examples suite or target a specific specification file for checking.

    # Build all examples
    lake build Examples
    
    # Build and check a single example
    lake lean Examples/Tutorial/Ring.lean