| <p align="center"> | |
| ``` | |
| βββββββ βββ ββββββββββ ββββββββ | |
| βββββββββββ βββββββββββββββββββ | |
| βββββββββββ βββββββββββββββββ | |
| βββββββ βββ βββββββββββββββββ | |
| βββ ββββββββββββ βββββββββββ | |
| βββ βββββββ βββ βββββββββββ | |
| βββ βββ ββββββ βββ ββββββββββ βββββββββββββββ βββ | |
| βββ ββββββββββββββ βββββββββββββββββββββββββββ ββββ | |
| βββ ββββββββββββββ ββββββ ββββββ βββ βββββββ | |
| ββββ βββββββββββββββ ββββββ ββββββ βββ βββββ | |
| βββββββ βββ βββββββββββββββββββββββββ βββ βββ | |
| βββββ βββ βββββββββββββββββββββ βββ βββ βββ | |
| ``` | |
| </p> | |
| <h3 align="center">Formal verification from NAND gates to proof certificates.</h3> | |
| <p align="center"> | |
| <img src="https://img.shields.io/badge/core-Haskell-5e5086?style=flat-square"/> | |
| <img src="https://img.shields.io/badge/backend-Fortran-734f96?style=flat-square"/> | |
| <img src="https://img.shields.io/badge/solver-CDCL+DPLL-blue?style=flat-square"/> | |
| <img src="https://img.shields.io/badge/kernel-80_LOC-brightgreen?style=flat-square"/> | |
| <img src="https://img.shields.io/badge/tests-20_passing-brightgreen?style=flat-square"/> | |
| <img src="https://img.shields.io/badge/deps-containers_only-black?style=flat-square"/> | |
| <img src="https://img.shields.io/badge/license-AGPL--3.0-red?style=flat-square"/> | |
| </p> | |
| --- | |
| ## What Is This? | |
| A self-contained formal verification engine built from first principles. No Z3. No SMT solver dependency. No Lean. No Coq. Just: | |
| - A source language (`.nf` files) where NAND is the only primitive | |
| - A compiler that elaborates definitions into Boolean circuits | |
| - A SAT solver (DPLL + CDCL with clause learning) that searches for proofs | |
| - A proof-producing backend that emits resolution certificates | |
| - A **trusted kernel** (~80 lines) that independently verifies those certificates | |
| The foundational principle: **the engine searches, the kernel decides.** | |
| ``` | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β β | |
| β THE SEPARATION β | |
| β β | |
| β SOLVER (complex, 1000+ LOC) KERNEL (simple, ~80 LOC) β | |
| β βββββββββββββββββββββββββ ββββββββββββββββββββββ β | |
| β β | |
| β Heuristics, backtracking, Resolution step checker β | |
| β clause learning, unit prop, Clause validation β | |
| β decision ordering, restarts Hash verification β | |
| β β | |
| β MAY HAVE BUGS MUST BE CORRECT β | |
| β (if buggy: proof won't verify) (if buggy: false validity) β | |
| β β | |
| β A bug in the solver = A bug in the kernel = β | |
| β "failed to find proof" "accepted invalid proof" β | |
| β (safe failure) (unsound β the only real risk) β | |
| β β | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| --- | |
| ## Quick Start | |
| ```bash | |
| git clone https://github.com/SNAPKITTYWEST/pure-validity | |
| cd pure-validity | |
| cabal build | |
| cabal run pure-validity -- examples/gates.nf | |
| ``` | |
| ``` | |
| Module: gates | |
| Properties: 16 | |
| [OK] not_true | |
| [OK] not_false | |
| [OK] and_tt | |
| [OK] and_tf | |
| [OK] and_ft | |
| [OK] and_ff | |
| [OK] or_tt | |
| [OK] or_tf | |
| [OK] or_ft | |
| [OK] or_ff | |
| [OK] xor_tt | |
| [OK] xor_tf | |
| [OK] xor_ft | |
| [OK] xor_ff | |
| 16/16 verified. | |
| ``` | |
| --- | |
| ## The Language β `.nf` files | |
| NAND is the only hardware primitive. Everything else is defined, not assumed. | |
| ``` | |
| -- gates.nf β derive all logic from NAND alone | |
| def not(x) = (x | x); | |
| def and(x y) = not((x | y)); | |
| def or(x y) = (not(x) | not(y)); | |
| def xor(x y) = ((x | (x | y)) | (y | (x | y))); | |
| -- Prove correctness of derived gates | |
| prove and_tt: and(true true) = true; | |
| prove xor_tf: xor(true false) = true; | |
| ``` | |
| ### Syntax Reference | |
| ``` | |
| ββββββββββββββββββββββ¦ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β CONSTRUCT β MEANING β | |
| β βββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββ£ | |
| β (a | b) β NAND β the only primitive gate β | |
| β def f(x y) = e; β Define a named circuit β | |
| β prove n: e; β State and verify a property β | |
| β assert e; β Verify without naming β | |
| β true / false β Boolean constants β | |
| β -- comment β Line comment β | |
| β module name; β Module declaration β | |
| ββββββββββββββββββββββ©ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| --- | |
| ## Verification Pipeline | |
| ``` | |
| .nf source file | |
| β | |
| βΌ | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β LEXER + PARSER β | |
| β Language/Lexer.hs + Language/Parser.hs β | |
| β Source text β Token stream β AST (Module of Stmts) β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βΌ | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β ELABORATOR β | |
| β Language/Elaborator.hs β | |
| β AST β Boolean IR (BExpr trees β NAND-only) β | |
| β Inlines function applications, resolves names β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βΌ | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β TSEITIN TRANSFORM β | |
| β SAT/CNF.hs β | |
| β BExpr β CNF (conjunctive normal form) β | |
| β Introduces auxiliary variables, linear blowup β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βΌ | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β SAT SOLVER (DPLL + CDCL) β | |
| β SAT/DPLL.hs + SAT/CDCL.hs β | |
| β Unit propagation β decision β conflict β backtrack β | |
| β Clause learning on conflict (CDCL) β | |
| β Proof-producing: records resolution steps β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βΌ | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β PROOF CERTIFICATE β | |
| β Proof/Certificate.hs + Proof/Produce.hs β | |
| β Resolution steps + SHA-256 hash β | |
| β Conclusion: Valid | Unsatisfiable | CounterExample β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βΌ | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β TRUSTED KERNEL (~80 LOC) β | |
| β Checker/Kernel.hs β | |
| β Independently verifies every resolution step β | |
| β Accepts or rejects the certificate β | |
| β THE ONLY CODE THAT MUST BE CORRECT β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βΌ | |
| [OK] Property verified / [FAIL] Counterexample found | |
| ``` | |
| --- | |
| ## Architecture β Why Two Layers? | |
| The insight from proof-carrying code (Necula 1997): separate the **search** from the **checking**. | |
| A solver can be arbitrarily complex β heuristics, restarts, clause deletion, VSIDS scoring. If it has a bug, it just fails to find the proof. The system remains sound. | |
| The kernel is trivial by comparison. It receives a claimed proof (sequence of resolution steps) and mechanically verifies each step: did resolving clause A with clause B on pivot variable P actually produce clause C? That's it. ~80 lines. Auditable by hand. | |
| ``` | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β β | |
| β Solver bug β "could not prove" (safe, retry with better β | |
| β heuristics or more time) β | |
| β β | |
| β Kernel bug β false validity claim (unsound β THE risk) β | |
| β But kernel is 80 LOC, auditable, testable β | |
| β β | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| --- | |
| ## Fortran Backend | |
| For hardware-scale verification (thousands of gates), the Fortran backend provides vectorized clause checking and bounded model checking: | |
| ```fortran | |
| ! bitvec_ops.f90 β bulk NAND evaluation + clause checking | |
| call bulk_clause_check(clauses, num_clauses, clause_lens, assignment, num_vars, satisfied) | |
| ! state_machine.f90 β bounded model checking with induction | |
| result = bmc_check(transition_gates, ..., init_state, state_width, bound) | |
| ``` | |
| The Fortran modules handle: | |
| - Vectorized NAND evaluation over flat gate arrays | |
| - Bulk satisfiability checking across all clauses simultaneously | |
| - Ripple-carry addition for arithmetic circuit verification | |
| - Bounded model checking (BMC) for sequential circuits | |
| - k-induction for unbounded property proofs | |
| --- | |
| ## Examples | |
| ``` | |
| βββββββββββββββββββββ¦βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β FILE β WHAT IT PROVES β | |
| β ββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββ£ | |
| β nand.nf β NAND truth table (the primitive) β | |
| β gates.nf β NOT/AND/OR/XOR all correct from NAND alone β | |
| β half_adder.nf β Binary arithmetic: sum and carry correct β | |
| β demorgan.nf β De Morgan's Laws hold for NAND-derived gates β | |
| β mux.nf β 2-to-1 multiplexer selects correctly β | |
| βββββββββββββββββββββ©βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| Run all examples: | |
| ```bash | |
| for f in examples/*.nf; do cabal run pure-validity -- "$f"; echo; done | |
| ``` | |
| --- | |
| ## Project Layout | |
| ``` | |
| pure-validity/ | |
| βββ pure-validity.cabal Build configuration | |
| βββ README.md This file | |
| β | |
| βββ src/ | |
| β βββ Main.hs Entry point β file β parse β prove β check | |
| β βββ Language/ | |
| β β βββ AST.hs Abstract syntax (Expr, Stmt, Module) | |
| β β βββ Lexer.hs Tokenizer (keywords, operators, idents) | |
| β β βββ Parser.hs Recursive descent parser | |
| β β βββ Elaborator.hs AST β Boolean IR (inline + resolve) | |
| β βββ IR/ | |
| β β βββ Boolean.hs BExpr type + eval + NAND/AND/OR/XOR | |
| β β βββ NAND.hs NAND normal form transformation | |
| β β βββ BitVec.hs Bit-vector arithmetic (add, eq, const) | |
| β βββ SAT/ | |
| β β βββ CNF.hs Clause/literal types + Tseitin transform | |
| β β βββ UnitProp.hs Unit propagation (BCP) | |
| β β βββ DPLL.hs Davis-Putnam-Logemann-Loveland solver | |
| β β βββ CDCL.hs Conflict-Driven Clause Learning solver | |
| β βββ Proof/ | |
| β β βββ Certificate.hs ProofStep, ProofCertificate types | |
| β β βββ Produce.hs Validity/UNSAT proof generation | |
| β βββ Checker/ | |
| β βββ Kernel.hs THE TRUSTED KERNEL (~80 LOC) | |
| β | |
| βββ fortran/ | |
| β βββ bitvec_ops.f90 Vectorized NAND + bulk clause check | |
| β βββ state_machine.f90 BMC + k-induction for sequential circuits | |
| β | |
| βββ examples/ | |
| β βββ nand.nf NAND primitive proofs | |
| β βββ gates.nf All gates from NAND | |
| β βββ half_adder.nf Arithmetic correctness | |
| β βββ demorgan.nf De Morgan's Laws | |
| β βββ mux.nf Multiplexer properties | |
| β | |
| βββ test/ | |
| βββ Spec.hs 20 tests β IR, solver, kernel, parser | |
| ``` | |
| --- | |
| ## Run Tests | |
| ```bash | |
| cabal test | |
| ``` | |
| ``` | |
| [OK] NAND truth table | |
| [OK] NOT from NAND | |
| [OK] AND from NAND | |
| [OK] OR from NAND | |
| [OK] XOR from NAND | |
| [OK] Half adder sum | |
| [OK] Half adder carry | |
| [OK] BitVec add 3+5=8 | |
| [OK] Tseitin preserves satisfiability | |
| [OK] DPLL finds SAT | |
| [OK] DPLL finds UNSAT | |
| [OK] Unit propagation | |
| [OK] Proof certificate valid | |
| [OK] Checker accepts valid | |
| [OK] Checker rejects invalid | |
| [OK] Parse module | |
| [OK] Elaborate module | |
| [OK] NAND normal form | |
| [OK] De Morgan via eval | |
| [OK] MUX correctness | |
| 20/20 tests passed. | |
| ``` | |
| --- | |
| ## Requirements | |
| - GHC 8.10+ (Haskell compiler) | |
| - Cabal 3.0+ | |
| - gfortran (for Fortran backend, optional) | |
| - Zero external solver dependencies (no Z3, no MiniSat, no SMT-LIB) | |
| ```bash | |
| # Install GHC + Cabal (if needed) | |
| curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh | |
| # Build and run | |
| cabal build | |
| cabal run pure-validity -- examples/gates.nf | |
| cabal test | |
| ``` | |
| --- | |
| ## Theory | |
| The verification approach combines: | |
| 1. **Tseitin transformation** β Boolean formula to CNF with linear blowup (not exponential) | |
| 2. **DPLL** β systematic backtracking search with unit propagation | |
| 3. **CDCL** β conflict-driven clause learning for exponential speedup on structured problems | |
| 4. **Resolution proofs** β the solver records why it concluded UNSAT | |
| 5. **Proof checking** β independent verification that each resolution step is valid | |
| To prove a property P holds: negate P, convert to CNF, prove UNSAT. If the negation is unsatisfiable, the original property is valid (true under all assignments). | |
| --- | |
| <p align="center"> | |
| <b>Built by Ahmad Ali Parr + SnapKitty Collective</b> | |
| </p> | |
| <p align="center"> | |
| ``` | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β β | |
| β The engine searches. β | |
| β The kernel decides. β | |
| β β | |
| β If the kernel is correct, the system is sound. β | |
| β The kernel is 80 lines. β | |
| β Read them yourself. β | |
| β β | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| </p> | |