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 (.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

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:

  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).


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.                                 β•‘
β•‘                                                      β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Space using Snapkitty/pure-validity 1

Collection including Snapkitty/pure-validity