YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
βββββββ βββ ββββββββββ ββββββββ
βββββββββββ βββββββββββββββββββ
βββββββββββ βββββββββββββββββ
βββββββ βββ βββββββββββββββββ
βββ ββββββββββββ βββββββββββ
βββ βββββββ βββ βββββββββββ
βββ βββ ββββββ βββ ββββββββββ βββββββββββββββ βββ
βββ ββββββββββββββ βββββββββββββββββββββββββββ ββββ
βββ ββββββββββββββ ββββββ ββββββ βββ βββββββ
ββββ βββββββββββββββ ββββββ ββββββ βββ βββββ
βββββββ βββ βββββββββββββββββββββββββ βββ βββ
βββββ βββ βββββββββββββββββββββ βββ βββ βββ
Formal verification from NAND gates to proof certificates.
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 (
.nffiles) 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
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:
! 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:
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
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)
# 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:
- Tseitin transformation β Boolean formula to CNF with linear blowup (not exponential)
- DPLL β systematic backtracking search with unit propagation
- CDCL β conflict-driven clause learning for exponential speedup on structured problems
- Resolution proofs β the solver records why it concluded UNSAT
- 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).
Built by Ahmad Ali Parr + SnapKitty Collective
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β The engine searches. β
β The kernel decides. β
β β
β If the kernel is correct, the system is sound. β
β The kernel is 80 lines. β
β Read them yourself. β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ