From First Principles to Production-Grade Verified Systems
Introduction: Why Testing Is Not Enough
- A History of Missed Bugs
- What Formal Verification Actually Means
- The Spectrum from Testing to Proofs
- How This Book Is Structured
Chapter 1: Properties, Specifications, and Invariants
- From Requirements to Precise Properties
- Preconditions and Postconditions: Contracts for Code
- Invariants: What Must Always Be True
- Assertions as Lightweight Verification
- State Machines and Behavioral Models
- Designing Specifications That Are Checkable
- Summary
Chapter 2: Logic and Mathematics for Verification
- Propositional Logic: Truth Tables and Equivalences
- Predicate Logic: Quantifiers and Properties Over Data
- Sets, Relations, and Functions as Specification Tools
- Boolean Algebra for Software Engineers
- Induction: Proving Things About Arbitrary Inputs
- Proof Techniques: Direct, Contradiction, Cases
- Summary
Chapter 3: Hoare Logic and Program Correctness
- Hoare Triples: The Language of Partial Correctness
- Rules of Inference for Imperative Programs
- P’ → P, {P} C {Q}, Q → Q’
- Weakest Preconditions: Reasoning Backwards
- Operational Semantics: Defining What Programs Mean
- Sequencing: ⟨C1, σ⟩ ⇓ σ’, ⟨C2, σ’⟩ ⇓ σ’’
- Total vs Partial Correctness and Termination
- Proof Trees for Real Code
- Summary
Chapter 4: Property-Based Testing as a Bridge to Formal Reasoning
- From Example Tests to Universal Properties
- QuickCheck, Hypothesis, and Property Frameworks
- Shrinking Counterexamples: Learning from Failure
- Invariants as Testable Properties
- When Property Testing Succeeds and Fails
- The Path from Properties to Proofs
- Summary
Chapter 5: SAT Solvers and Boolean Reasoning
- The Satisfiability Problem and Its Ubiquity
- Conjunctive Normal Form: Encoding Problems as Logic
- How SAT Solvers Work: DPLL and CDCL
- Using SAT Solvers in Practice: MiniSat, Z3
- Encoding Real Constraints for SAT
- Limits of Pure Boolean Reasoning
- Summary
Chapter 6: SMT Solvers and Constraint Solving
- From SAT to SMT: Adding Theories
- Core Theories: Arithmetic, Arrays, Bitvectors, Strings
- Z3 and Other Major SMT Solvers
- Encoding Programs as Constraints
- Solver-Aided Programming Patterns
- Interpreting Sat/Unsat and Models
- Summary
Chapter 7: Symbolic Execution and Path Analysis
- Symbolic Values and Path Conditions
- Exploring Branches Systematically
- Concolic Execution: Mixing Concrete and Symbolic
- Bounded Model Checking via Symbolic Execution
- Tools: KLEE, angr, CBMC
- Path Explosion and Practical Mitigations
- Summary
Chapter 8: Abstract Interpretation and Static Analysis
- The Idea of Abstraction: Precision vs Soundness
- Lattices and Fixpoints Made Intuitive
- Common Analyses: Nullability, Ranges, Taint
- Frama-C and the WP Plugin
- SPARK/Ada for Safety-Critical Code
- Trade-offs Between Soundness and Scalability
- Summary
Chapter 9: Model Checking and Temporal Logic
- State Spaces and Transition Systems
- Linear-Time vs Branching-Time Temporal Logic
- LTL and CTL: Specifying Behavioral Properties
- How Model Checkers Explore State Spaces
- TLA+ for Distributed Systems Design
- State Explosion and Symmetry Breaking
- Summary
Chapter 10: Deductive Verification with Contracts and Annotations
- The Deductive Verification Pipeline
- Dafny: Syntax, Contracts, and Automation
- Loop Invariants and Recursive Functions
- Framing Conditions and Modularity
- Verus and Rust Verification
- Debugging Failed Proofs
- Summary
Chapter 11: Separation Logic and Memory Reasoning
- The Problem of Shared Mutable State
- Separating Conjunctions and Spatial Reasoning
- Points-to Assertions and Heap Predicates
- Verifying Pointer Manipulation
- Prusti, Creusot, and Rust Verification
- Concurrent Separation Logic Basics
- Summary
Chapter 12: Concurrent Program Verification
- What Goes Wrong in Concurrent Code
- Linearizability and Atomicity Specifications
- Race Detection vs Race Proofs
- Lock-Based Reasoning and Ownership
- Verifying Concurrent Data Structures
- Tools: IronFleet, F*, Viper
- Summary
Chapter 13: Distributed Systems and Protocol Verification
- The Unique Challenges of Distributed Verification
- Specifying Consensus and Replication
- Alloy for Lightweight Structural Analysis
- Verifying Paxos, Raft, and CRDTs
- Handling Timeouts, Failures, and Network Partitions
- IronFleet: Verified End-to-End Distributed Systems
- Summary
Chapter 14: Theorem Proving with Proof Assistants
- When You Need a Proof Assistant
- Dependent Types and Propositions-as-Types
- Interactive Proof Development in Lean
- Tactics, Automation, and Proof Terms
- Coq/Rocq for Certified Software
- Isabelle/HOL for Large-Scale Verification
- Summary
Chapter 15: Verified Compilers and Systems Software
- Why Verify Compilers? The CompCert Story
- Verified Operating System Kernels (seL4, Fuchsia)
- Cryptographic Implementations in F* and Others
- Proof-Carrying Code and Capabilities
- Smart Contract Verification on Blockchains
- Lessons from Million-Line Verified Systems
- Summary
Chapter 16: Engineering Practice — Adoption, Workflows, and Culture
- Choosing What to Verify: Risk vs Effort
- The Trusted Computing Base and Its Limits
- Integrating Verification into CI Pipelines
- Specification Review and Proof Maintenance
- Combining Verification with Testing and Fuzzing
- Introducing Formal Methods to Engineering Teams
- Summary
Major Case Study: From Tests to Verified System
- The Component: Requirements and Initial Implementation
- Baseline Testing and Its Blind Spots
- Adding Property-Based Testing
- SMT-Based Contract Checking with Dafny
- Model Checking the State Machine in TLA+
- Machine-Checked Proofs for Critical Properties
- CI Integration and Regression Guarantees
- What We Learned: Costs, Benefits, Trade-offs
- Summary
Conclusion: The Future of Verified Software Engineering
- Where Formal Verification Has Succeeded
- AI and Language Models in Verification Workflows
- The Remaining Gaps Between Research and Practice
- A Pragmatic Philosophy for Verified Software
- Getting Started Tomorrow