SNAPKITTYWEST commited on
Commit
c2e3084
Β·
verified Β·
1 Parent(s): 56de343

Sync with GitHub, license metadata from LICENSE files, commercial license notice

Browse files
Files changed (1) hide show
  1. README.md +418 -398
README.md CHANGED
@@ -1,398 +1,418 @@
1
- <p align="center">
2
-
3
- ```
4
- β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
5
- β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•
6
- β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
7
- β–ˆβ–ˆβ•”β•β•β•β• β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•
8
- β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
9
- β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•šβ•β•β•β•β•β•β•
10
-
11
- β–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—
12
- β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β•šβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•
13
- β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•
14
- β•šβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ•”β•
15
- β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘
16
- β•šβ•β•β•β• β•šβ•β• β•šβ•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β• β•šβ•β•
17
- ```
18
-
19
- </p>
20
-
21
- <h3 align="center">Formal verification from NAND gates to proof certificates.</h3>
22
-
23
- <p align="center">
24
- <img src="https://img.shields.io/badge/core-Haskell-5e5086?style=flat-square"/>
25
- <img src="https://img.shields.io/badge/backend-Fortran-734f96?style=flat-square"/>
26
- <img src="https://img.shields.io/badge/solver-CDCL+DPLL-blue?style=flat-square"/>
27
- <img src="https://img.shields.io/badge/kernel-80_LOC-brightgreen?style=flat-square"/>
28
- <img src="https://img.shields.io/badge/tests-20_passing-brightgreen?style=flat-square"/>
29
- <img src="https://img.shields.io/badge/deps-containers_only-black?style=flat-square"/>
30
- <img src="https://img.shields.io/badge/license-AGPL--3.0-red?style=flat-square"/>
31
- </p>
32
-
33
- ---
34
-
35
- ## What Is This?
36
-
37
- A self-contained formal verification engine built from first principles. No Z3. No SMT solver dependency. No Lean. No Coq. Just:
38
-
39
- - A source language (`.nf` files) where NAND is the only primitive
40
- - A compiler that elaborates definitions into Boolean circuits
41
- - A SAT solver (DPLL + CDCL with clause learning) that searches for proofs
42
- - A proof-producing backend that emits resolution certificates
43
- - A **trusted kernel** (~80 lines) that independently verifies those certificates
44
-
45
- The foundational principle: **the engine searches, the kernel decides.**
46
-
47
- ```
48
- ╔══════════════════════════════════════════════════════════════════════════╗
49
- β•‘ β•‘
50
- β•‘ THE SEPARATION β•‘
51
- β•‘ β•‘
52
- β•‘ SOLVER (complex, 1000+ LOC) KERNEL (simple, ~80 LOC) β•‘
53
- β•‘ ───────────────────────── ────────────────────── β•‘
54
- β•‘ β•‘
55
- β•‘ Heuristics, backtracking, Resolution step checker β•‘
56
- β•‘ clause learning, unit prop, Clause validation β•‘
57
- β•‘ decision ordering, restarts Hash verification β•‘
58
- β•‘ β•‘
59
- β•‘ MAY HAVE BUGS MUST BE CORRECT β•‘
60
- β•‘ (if buggy: proof won't verify) (if buggy: false validity) β•‘
61
- β•‘ β•‘
62
- β•‘ A bug in the solver = A bug in the kernel = β•‘
63
- β•‘ "failed to find proof" "accepted invalid proof" β•‘
64
- β•‘ (safe failure) (unsound β€” the only real risk) β•‘
65
- β•‘ β•‘
66
- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
67
- ```
68
-
69
- ---
70
-
71
- ## Quick Start
72
-
73
- ```bash
74
- git clone https://github.com/SNAPKITTYWEST/pure-validity
75
- cd pure-validity
76
- cabal build
77
- cabal run pure-validity -- examples/gates.nf
78
- ```
79
-
80
- ```
81
- Module: gates
82
- Properties: 16
83
-
84
- [OK] not_true
85
- [OK] not_false
86
- [OK] and_tt
87
- [OK] and_tf
88
- [OK] and_ft
89
- [OK] and_ff
90
- [OK] or_tt
91
- [OK] or_tf
92
- [OK] or_ft
93
- [OK] or_ff
94
- [OK] xor_tt
95
- [OK] xor_tf
96
- [OK] xor_ft
97
- [OK] xor_ff
98
-
99
- 16/16 verified.
100
- ```
101
-
102
- ---
103
-
104
- ## The Language β€” `.nf` files
105
-
106
- NAND is the only hardware primitive. Everything else is defined, not assumed.
107
-
108
- ```
109
- -- gates.nf β€” derive all logic from NAND alone
110
-
111
- def not(x) = (x | x);
112
-
113
- def and(x y) = not((x | y));
114
-
115
- def or(x y) = (not(x) | not(y));
116
-
117
- def xor(x y) = ((x | (x | y)) | (y | (x | y)));
118
-
119
- -- Prove correctness of derived gates
120
- prove and_tt: and(true true) = true;
121
- prove xor_tf: xor(true false) = true;
122
- ```
123
-
124
- ### Syntax Reference
125
-
126
- ```
127
- ╔════════════════════╦═══════════════════════════════════════════════╗
128
- β•‘ CONSTRUCT β•‘ MEANING β•‘
129
- ╠════════════════════╬═══════════════════════════════════════════════╣
130
- β•‘ (a | b) β•‘ NAND β€” the only primitive gate β•‘
131
- β•‘ def f(x y) = e; β•‘ Define a named circuit β•‘
132
- β•‘ prove n: e; β•‘ State and verify a property β•‘
133
- β•‘ assert e; β•‘ Verify without naming β•‘
134
- β•‘ true / false β•‘ Boolean constants β•‘
135
- β•‘ -- comment β•‘ Line comment β•‘
136
- β•‘ module name; β•‘ Module declaration β•‘
137
- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•©β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
138
- ```
139
-
140
- ---
141
-
142
- ## Verification Pipeline
143
-
144
- ```
145
- .nf source file
146
- β”‚
147
- β–Ό
148
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
149
- β”‚ LEXER + PARSER β”‚
150
- β”‚ Language/Lexer.hs + Language/Parser.hs β”‚
151
- β”‚ Source text β†’ Token stream β†’ AST (Module of Stmts) β”‚
152
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
153
- β”‚
154
- β–Ό
155
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
156
- β”‚ ELABORATOR β”‚
157
- β”‚ Language/Elaborator.hs β”‚
158
- β”‚ AST β†’ Boolean IR (BExpr trees β€” NAND-only) β”‚
159
- β”‚ Inlines function applications, resolves names β”‚
160
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
161
- β”‚
162
- β–Ό
163
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
164
- β”‚ TSEITIN TRANSFORM β”‚
165
- β”‚ SAT/CNF.hs β”‚
166
- β”‚ BExpr β†’ CNF (conjunctive normal form) β”‚
167
- β”‚ Introduces auxiliary variables, linear blowup β”‚
168
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
169
- β”‚
170
- β–Ό
171
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
172
- β”‚ SAT SOLVER (DPLL + CDCL) β”‚
173
- β”‚ SAT/DPLL.hs + SAT/CDCL.hs β”‚
174
- β”‚ Unit propagation β†’ decision β†’ conflict β†’ backtrack β”‚
175
- β”‚ Clause learning on conflict (CDCL) β”‚
176
- β”‚ Proof-producing: records resolution steps β”‚
177
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
178
- β”‚
179
- β–Ό
180
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
181
- β”‚ PROOF CERTIFICATE β”‚
182
- β”‚ Proof/Certificate.hs + Proof/Produce.hs β”‚
183
- β”‚ Resolution steps + SHA-256 hash β”‚
184
- β”‚ Conclusion: Valid | Unsatisfiable | CounterExample β”‚
185
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
186
- β”‚
187
- β–Ό
188
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
189
- β”‚ TRUSTED KERNEL (~80 LOC) β”‚
190
- β”‚ Checker/Kernel.hs β”‚
191
- β”‚ Independently verifies every resolution step β”‚
192
- β”‚ Accepts or rejects the certificate β”‚
193
- β”‚ THE ONLY CODE THAT MUST BE CORRECT β”‚
194
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
195
- β”‚
196
- β–Ό
197
- [OK] Property verified / [FAIL] Counterexample found
198
- ```
199
-
200
- ---
201
-
202
- ## Architecture β€” Why Two Layers?
203
-
204
- The insight from proof-carrying code (Necula 1997): separate the **search** from the **checking**.
205
-
206
- 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.
207
-
208
- 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.
209
-
210
- ```
211
- ╔══════════════════════════════════════════════════════════════╗
212
- β•‘ β•‘
213
- β•‘ Solver bug β†’ "could not prove" (safe, retry with better β•‘
214
- β•‘ heuristics or more time) β•‘
215
- β•‘ β•‘
216
- β•‘ Kernel bug β†’ false validity claim (unsound β€” THE risk) β•‘
217
- β•‘ But kernel is 80 LOC, auditable, testable β•‘
218
- β•‘ β•‘
219
- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
220
- ```
221
-
222
- ---
223
-
224
- ## Fortran Backend
225
-
226
- For hardware-scale verification (thousands of gates), the Fortran backend provides vectorized clause checking and bounded model checking:
227
-
228
- ```fortran
229
- ! bitvec_ops.f90 β€” bulk NAND evaluation + clause checking
230
- call bulk_clause_check(clauses, num_clauses, clause_lens, assignment, num_vars, satisfied)
231
-
232
- ! state_machine.f90 β€” bounded model checking with induction
233
- result = bmc_check(transition_gates, ..., init_state, state_width, bound)
234
- ```
235
-
236
- The Fortran modules handle:
237
- - Vectorized NAND evaluation over flat gate arrays
238
- - Bulk satisfiability checking across all clauses simultaneously
239
- - Ripple-carry addition for arithmetic circuit verification
240
- - Bounded model checking (BMC) for sequential circuits
241
- - k-induction for unbounded property proofs
242
-
243
- ---
244
-
245
- ## Examples
246
-
247
- ```
248
- ╔═══════════════════╦══════════════════════════════════════════════════╗
249
- β•‘ FILE β•‘ WHAT IT PROVES β•‘
250
- ╠═══════════════════╬══════════════════════════════════════════════════╣
251
- β•‘ nand.nf β•‘ NAND truth table (the primitive) β•‘
252
- β•‘ gates.nf β•‘ NOT/AND/OR/XOR all correct from NAND alone β•‘
253
- β•‘ half_adder.nf β•‘ Binary arithmetic: sum and carry correct β•‘
254
- β•‘ demorgan.nf β•‘ De Morgan's Laws hold for NAND-derived gates β•‘
255
- β•‘ mux.nf β•‘ 2-to-1 multiplexer selects correctly β•‘
256
- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•©β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
257
- ```
258
-
259
- Run all examples:
260
-
261
- ```bash
262
- for f in examples/*.nf; do cabal run pure-validity -- "$f"; echo; done
263
- ```
264
-
265
- ---
266
-
267
- ## Project Layout
268
-
269
- ```
270
- pure-validity/
271
- β”œβ”€β”€ pure-validity.cabal Build configuration
272
- β”œβ”€β”€ README.md This file
273
- β”‚
274
- β”œβ”€β”€ src/
275
- β”‚ β”œβ”€β”€ Main.hs Entry point β€” file β†’ parse β†’ prove β†’ check
276
- β”‚ β”œβ”€β”€ Language/
277
- β”‚ β”‚ β”œβ”€β”€ AST.hs Abstract syntax (Expr, Stmt, Module)
278
- β”‚ β”‚ β”œβ”€β”€ Lexer.hs Tokenizer (keywords, operators, idents)
279
- β”‚ β”‚ β”œβ”€β”€ Parser.hs Recursive descent parser
280
- β”‚ β”‚ └── Elaborator.hs AST β†’ Boolean IR (inline + resolve)
281
- β”‚ β”œβ”€β”€ IR/
282
- β”‚ β”‚ β”œβ”€β”€ Boolean.hs BExpr type + eval + NAND/AND/OR/XOR
283
- β”‚ β”‚ β”œβ”€β”€ NAND.hs NAND normal form transformation
284
- β”‚ β”‚ └── BitVec.hs Bit-vector arithmetic (add, eq, const)
285
- β”‚ β”œβ”€β”€ SAT/
286
- β”‚ β”‚ β”œβ”€β”€ CNF.hs Clause/literal types + Tseitin transform
287
- β”‚ β”‚ β”œβ”€β”€ UnitProp.hs Unit propagation (BCP)
288
- β”‚ β”‚ β”œβ”€β”€ DPLL.hs Davis-Putnam-Logemann-Loveland solver
289
- β”‚ β”‚ └── CDCL.hs Conflict-Driven Clause Learning solver
290
- β”‚ β”œβ”€β”€ Proof/
291
- β”‚ β”‚ β”œβ”€β”€ Certificate.hs ProofStep, ProofCertificate types
292
- β”‚ β”‚ └── Produce.hs Validity/UNSAT proof generation
293
- β”‚ └── Checker/
294
- β”‚ └── Kernel.hs THE TRUSTED KERNEL (~80 LOC)
295
- β”‚
296
- β”œβ”€β”€ fortran/
297
- β”‚ β”œβ”€β”€ bitvec_ops.f90 Vectorized NAND + bulk clause check
298
- β”‚ └── state_machine.f90 BMC + k-induction for sequential circuits
299
- β”‚
300
- β”œβ”€β”€ examples/
301
- β”‚ β”œβ”€β”€ nand.nf NAND primitive proofs
302
- β”‚ β”œβ”€β”€ gates.nf All gates from NAND
303
- β”‚ β”œβ”€β”€ half_adder.nf Arithmetic correctness
304
- β”‚ β”œβ”€β”€ demorgan.nf De Morgan's Laws
305
- β”‚ └── mux.nf Multiplexer properties
306
- β”‚
307
- └── test/
308
- └── Spec.hs 20 tests β€” IR, solver, kernel, parser
309
- ```
310
-
311
- ---
312
-
313
- ## Run Tests
314
-
315
- ```bash
316
- cabal test
317
- ```
318
-
319
- ```
320
- [OK] NAND truth table
321
- [OK] NOT from NAND
322
- [OK] AND from NAND
323
- [OK] OR from NAND
324
- [OK] XOR from NAND
325
- [OK] Half adder sum
326
- [OK] Half adder carry
327
- [OK] BitVec add 3+5=8
328
- [OK] Tseitin preserves satisfiability
329
- [OK] DPLL finds SAT
330
- [OK] DPLL finds UNSAT
331
- [OK] Unit propagation
332
- [OK] Proof certificate valid
333
- [OK] Checker accepts valid
334
- [OK] Checker rejects invalid
335
- [OK] Parse module
336
- [OK] Elaborate module
337
- [OK] NAND normal form
338
- [OK] De Morgan via eval
339
- [OK] MUX correctness
340
-
341
- 20/20 tests passed.
342
- ```
343
-
344
- ---
345
-
346
- ## Requirements
347
-
348
- - GHC 8.10+ (Haskell compiler)
349
- - Cabal 3.0+
350
- - gfortran (for Fortran backend, optional)
351
- - Zero external solver dependencies (no Z3, no MiniSat, no SMT-LIB)
352
-
353
- ```bash
354
- # Install GHC + Cabal (if needed)
355
- curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
356
-
357
- # Build and run
358
- cabal build
359
- cabal run pure-validity -- examples/gates.nf
360
- cabal test
361
- ```
362
-
363
- ---
364
-
365
- ## Theory
366
-
367
- The verification approach combines:
368
-
369
- 1. **Tseitin transformation** β€” Boolean formula to CNF with linear blowup (not exponential)
370
- 2. **DPLL** β€” systematic backtracking search with unit propagation
371
- 3. **CDCL** β€” conflict-driven clause learning for exponential speedup on structured problems
372
- 4. **Resolution proofs** β€” the solver records why it concluded UNSAT
373
- 5. **Proof checking** β€” independent verification that each resolution step is valid
374
-
375
- 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).
376
-
377
- ---
378
-
379
- <p align="center">
380
- <b>Built by Ahmad Ali Parr + SnapKitty Collective</b>
381
- </p>
382
-
383
- <p align="center">
384
-
385
- ```
386
- ╔══════════════════════════════════════════════════════╗
387
- β•‘ β•‘
388
- β•‘ The engine searches. β•‘
389
- β•‘ The kernel decides. β•‘
390
- β•‘ β•‘
391
- β•‘ If the kernel is correct, the system is sound. β•‘
392
- β•‘ The kernel is 80 lines. β•‘
393
- β•‘ Read them yourself. β•‘
394
- β•‘ β•‘
395
- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
396
- ```
397
-
398
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: agpl-3.0
3
+ tags:
4
+ - snapkitty
5
+ ---
6
+
7
+ <p align="center">
8
+
9
+ ```
10
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
11
+ β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•
12
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
13
+ β–ˆβ–ˆβ•”β•β•β•β• β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•
14
+ β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
15
+ β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•šβ•β•β•β•β•β•β•
16
+
17
+ β–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—
18
+ β–ˆοΏ½οΏ½οΏ½β•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β•šβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•
19
+ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•
20
+ β•šβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ•”β•
21
+ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘
22
+ β•šβ•β•β•β• β•šβ•β• β•šβ•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β• β•šβ•β•
23
+ ```
24
+
25
+ </p>
26
+
27
+ <h3 align="center">Formal verification from NAND gates to proof certificates.</h3>
28
+
29
+ <p align="center">
30
+ <img src="https://img.shields.io/badge/core-Haskell-5e5086?style=flat-square"/>
31
+ <img src="https://img.shields.io/badge/backend-Fortran-734f96?style=flat-square"/>
32
+ <img src="https://img.shields.io/badge/solver-CDCL+DPLL-blue?style=flat-square"/>
33
+ <img src="https://img.shields.io/badge/kernel-80_LOC-brightgreen?style=flat-square"/>
34
+ <img src="https://img.shields.io/badge/tests-20_passing-brightgreen?style=flat-square"/>
35
+ <img src="https://img.shields.io/badge/deps-containers_only-black?style=flat-square"/>
36
+ <img src="https://img.shields.io/badge/license-AGPL--3.0-red?style=flat-square"/>
37
+ </p>
38
+
39
+ ---
40
+
41
+ ## What Is This?
42
+
43
+ A self-contained formal verification engine built from first principles. No Z3. No SMT solver dependency. No Lean. No Coq. Just:
44
+
45
+ - A source language (`.nf` files) where NAND is the only primitive
46
+ - A compiler that elaborates definitions into Boolean circuits
47
+ - A SAT solver (DPLL + CDCL with clause learning) that searches for proofs
48
+ - A proof-producing backend that emits resolution certificates
49
+ - A **trusted kernel** (~80 lines) that independently verifies those certificates
50
+
51
+ The foundational principle: **the engine searches, the kernel decides.**
52
+
53
+ ```
54
+ ╔══════════════════════════════════════════════════════════════════════════╗
55
+ β•‘ β•‘
56
+ β•‘ THE SEPARATION β•‘
57
+ β•‘ β•‘
58
+ β•‘ SOLVER (complex, 1000+ LOC) KERNEL (simple, ~80 LOC) β•‘
59
+ β•‘ ───────────────────────── ────────────────────── β•‘
60
+ β•‘ β•‘
61
+ β•‘ Heuristics, backtracking, Resolution step checker β•‘
62
+ β•‘ clause learning, unit prop, Clause validation β•‘
63
+ β•‘ decision ordering, restarts Hash verification β•‘
64
+ β•‘ β•‘
65
+ β•‘ MAY HAVE BUGS MUST BE CORRECT β•‘
66
+ β•‘ (if buggy: proof won't verify) (if buggy: false validity) β•‘
67
+ β•‘ β•‘
68
+ β•‘ A bug in the solver = A bug in the kernel = β•‘
69
+ β•‘ "failed to find proof" "accepted invalid proof" β•‘
70
+ β•‘ (safe failure) (unsound β€” the only real risk) β•‘
71
+ β•‘ β•‘
72
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Quick Start
78
+
79
+ ```bash
80
+ git clone https://github.com/SNAPKITTYWEST/pure-validity
81
+ cd pure-validity
82
+ cabal build
83
+ cabal run pure-validity -- examples/gates.nf
84
+ ```
85
+
86
+ ```
87
+ Module: gates
88
+ Properties: 16
89
+
90
+ [OK] not_true
91
+ [OK] not_false
92
+ [OK] and_tt
93
+ [OK] and_tf
94
+ [OK] and_ft
95
+ [OK] and_ff
96
+ [OK] or_tt
97
+ [OK] or_tf
98
+ [OK] or_ft
99
+ [OK] or_ff
100
+ [OK] xor_tt
101
+ [OK] xor_tf
102
+ [OK] xor_ft
103
+ [OK] xor_ff
104
+
105
+ 16/16 verified.
106
+ ```
107
+
108
+ ---
109
+
110
+ ## The Language β€” `.nf` files
111
+
112
+ NAND is the only hardware primitive. Everything else is defined, not assumed.
113
+
114
+ ```
115
+ -- gates.nf β€” derive all logic from NAND alone
116
+
117
+ def not(x) = (x | x);
118
+
119
+ def and(x y) = not((x | y));
120
+
121
+ def or(x y) = (not(x) | not(y));
122
+
123
+ def xor(x y) = ((x | (x | y)) | (y | (x | y)));
124
+
125
+ -- Prove correctness of derived gates
126
+ prove and_tt: and(true true) = true;
127
+ prove xor_tf: xor(true false) = true;
128
+ ```
129
+
130
+ ### Syntax Reference
131
+
132
+ ```
133
+ ╔════════════════════╦═══════════════════════════════════════════════╗
134
+ β•‘ CONSTRUCT β•‘ MEANING β•‘
135
+ ╠════════════════════╬═══════════════════════════════════════════════╣
136
+ β•‘ (a | b) β•‘ NAND β€” the only primitive gate β•‘
137
+ β•‘ def f(x y) = e; β•‘ Define a named circuit β•‘
138
+ β•‘ prove n: e; β•‘ State and verify a property β•‘
139
+ β•‘ assert e; β•‘ Verify without naming β•‘
140
+ β•‘ true / false β•‘ Boolean constants β•‘
141
+ β•‘ -- comment β•‘ Line comment β•‘
142
+ β•‘ module name; β•‘ Module declaration β•‘
143
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•©β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Verification Pipeline
149
+
150
+ ```
151
+ .nf source file
152
+ β”‚
153
+ β–Ό
154
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
155
+ β”‚ LEXER + PARSER β”‚
156
+ β”‚ Language/Lexer.hs + Language/Parser.hs β”‚
157
+ β”‚ Source text β†’ Token stream β†’ AST (Module of Stmts) β”‚
158
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
159
+ β”‚
160
+ β–Ό
161
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
162
+ β”‚ ELABORATOR β”‚
163
+ β”‚ Language/Elaborator.hs β”‚
164
+ β”‚ AST β†’ Boolean IR (BExpr trees β€” NAND-only) β”‚
165
+ β”‚ Inlines function applications, resolves names β”‚
166
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
167
+ β”‚
168
+ β–Ό
169
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
170
+ β”‚ TSEITIN TRANSFORM β”‚
171
+ β”‚ SAT/CNF.hs β”‚
172
+ β”‚ BExpr β†’ CNF (conjunctive normal form) β”‚
173
+ β”‚ Introduces auxiliary variables, linear blowup β”‚
174
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
175
+ β”‚
176
+ β–Ό
177
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
178
+ β”‚ SAT SOLVER (DPLL + CDCL) β”‚
179
+ β”‚ SAT/DPLL.hs + SAT/CDCL.hs β”‚
180
+ β”‚ Unit propagation β†’ decision β†’ conflict β†’ backtrack β”‚
181
+ β”‚ Clause learning on conflict (CDCL) β”‚
182
+ β”‚ Proof-producing: records resolution steps β”‚
183
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
184
+ β”‚
185
+ β–Ό
186
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
187
+ β”‚ PROOF CERTIFICATE β”‚
188
+ β”‚ Proof/Certificate.hs + Proof/Produce.hs β”‚
189
+ β”‚ Resolution steps + SHA-256 hash β”‚
190
+ β”‚ Conclusion: Valid | Unsatisfiable | CounterExample β”‚
191
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
192
+ β”‚
193
+ β–Ό
194
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
195
+ β”‚ TRUSTED KERNEL (~80 LOC) β”‚
196
+ β”‚ Checker/Kernel.hs β”‚
197
+ β”‚ Independently verifies every resolution step β”‚
198
+ β”‚ Accepts or rejects the certificate β”‚
199
+ β”‚ THE ONLY CODE THAT MUST BE CORRECT β”‚
200
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€οΏ½οΏ½οΏ½β”€β”€β”€β”€β”€β”€β”˜
201
+ β”‚
202
+ β–Ό
203
+ [OK] Property verified / [FAIL] Counterexample found
204
+ ```
205
+
206
+ ---
207
+
208
+ ## Architecture β€” Why Two Layers?
209
+
210
+ The insight from proof-carrying code (Necula 1997): separate the **search** from the **checking**.
211
+
212
+ 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.
213
+
214
+ 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.
215
+
216
+ ```
217
+ ╔══════════════════════════════════════════════════════════════╗
218
+ β•‘ β•‘
219
+ β•‘ Solver bug β†’ "could not prove" (safe, retry with better β•‘
220
+ β•‘ heuristics or more time) β•‘
221
+ β•‘ β•‘
222
+ β•‘ Kernel bug β†’ false validity claim (unsound β€” THE risk) β•‘
223
+ β•‘ But kernel is 80 LOC, auditable, testable β•‘
224
+ β•‘ β•‘
225
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
226
+ ```
227
+
228
+ ---
229
+
230
+ ## Fortran Backend
231
+
232
+ For hardware-scale verification (thousands of gates), the Fortran backend provides vectorized clause checking and bounded model checking:
233
+
234
+ ```fortran
235
+ ! bitvec_ops.f90 β€” bulk NAND evaluation + clause checking
236
+ call bulk_clause_check(clauses, num_clauses, clause_lens, assignment, num_vars, satisfied)
237
+
238
+ ! state_machine.f90 β€” bounded model checking with induction
239
+ result = bmc_check(transition_gates, ..., init_state, state_width, bound)
240
+ ```
241
+
242
+ The Fortran modules handle:
243
+ - Vectorized NAND evaluation over flat gate arrays
244
+ - Bulk satisfiability checking across all clauses simultaneously
245
+ - Ripple-carry addition for arithmetic circuit verification
246
+ - Bounded model checking (BMC) for sequential circuits
247
+ - k-induction for unbounded property proofs
248
+
249
+ ---
250
+
251
+ ## Examples
252
+
253
+ ```
254
+ ╔═══════════════════╦══════════════════════════════════════════════════╗
255
+ β•‘ FILE β•‘ WHAT IT PROVES β•‘
256
+ ╠═══════════════════╬══════════════════════════════════════════════════╣
257
+ β•‘ nand.nf β•‘ NAND truth table (the primitive) β•‘
258
+ β•‘ gates.nf β•‘ NOT/AND/OR/XOR all correct from NAND alone β•‘
259
+ β•‘ half_adder.nf β•‘ Binary arithmetic: sum and carry correct β•‘
260
+ β•‘ demorgan.nf β•‘ De Morgan's Laws hold for NAND-derived gates β•‘
261
+ β•‘ mux.nf β•‘ 2-to-1 multiplexer selects correctly β•‘
262
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•©β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
263
+ ```
264
+
265
+ Run all examples:
266
+
267
+ ```bash
268
+ for f in examples/*.nf; do cabal run pure-validity -- "$f"; echo; done
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Project Layout
274
+
275
+ ```
276
+ pure-validity/
277
+ β”œβ”€β”€ pure-validity.cabal Build configuration
278
+ β”œβ”€β”€ README.md This file
279
+ β”‚
280
+ β”œβ”€β”€ src/
281
+ β”‚ β”œβ”€β”€ Main.hs Entry point β€” file β†’ parse β†’ prove β†’ check
282
+ β”‚ β”œβ”€β”€ Language/
283
+ β”‚ β”‚ β”œβ”€β”€ AST.hs Abstract syntax (Expr, Stmt, Module)
284
+ β”‚ β”‚ β”œβ”€β”€ Lexer.hs Tokenizer (keywords, operators, idents)
285
+ β”‚ β”‚ β”œβ”€β”€ Parser.hs Recursive descent parser
286
+ β”‚ β”‚ └── Elaborator.hs AST β†’ Boolean IR (inline + resolve)
287
+ β”‚ β”œβ”€β”€ IR/
288
+ β”‚ β”‚ β”œβ”€β”€ Boolean.hs BExpr type + eval + NAND/AND/OR/XOR
289
+ β”‚ β”‚ β”œβ”€β”€ NAND.hs NAND normal form transformation
290
+ β”‚ β”‚ └── BitVec.hs Bit-vector arithmetic (add, eq, const)
291
+ β”‚ β”œβ”€β”€ SAT/
292
+ β”‚ β”‚ β”œβ”€β”€ CNF.hs Clause/literal types + Tseitin transform
293
+ β”‚ β”‚ β”œβ”€β”€ UnitProp.hs Unit propagation (BCP)
294
+ β”‚ β”‚ β”œβ”€β”€ DPLL.hs Davis-Putnam-Logemann-Loveland solver
295
+ β”‚ β”‚ └── CDCL.hs Conflict-Driven Clause Learning solver
296
+ β”‚ β”œβ”€β”€ Proof/
297
+ β”‚ β”‚ β”œβ”€β”€ Certificate.hs ProofStep, ProofCertificate types
298
+ β”‚ β”‚ └── Produce.hs Validity/UNSAT proof generation
299
+ β”‚ └── Checker/
300
+ β”‚ └── Kernel.hs THE TRUSTED KERNEL (~80 LOC)
301
+ β”‚
302
+ β”œβ”€β”€ fortran/
303
+ β”‚ β”œβ”€β”€ bitvec_ops.f90 Vectorized NAND + bulk clause check
304
+ β”‚ └── state_machine.f90 BMC + k-induction for sequential circuits
305
+ β”‚
306
+ β”œβ”€β”€ examples/
307
+ β”‚ β”œβ”€β”€ nand.nf NAND primitive proofs
308
+ β”‚ β”œβ”€β”€ gates.nf All gates from NAND
309
+ β”‚ β”œβ”€β”€ half_adder.nf Arithmetic correctness
310
+ β”‚ β”œβ”€β”€ demorgan.nf De Morgan's Laws
311
+ β”‚ └── mux.nf Multiplexer properties
312
+ β”‚
313
+ └── test/
314
+ └── Spec.hs 20 tests β€” IR, solver, kernel, parser
315
+ ```
316
+
317
+ ---
318
+
319
+ ## Run Tests
320
+
321
+ ```bash
322
+ cabal test
323
+ ```
324
+
325
+ ```
326
+ [OK] NAND truth table
327
+ [OK] NOT from NAND
328
+ [OK] AND from NAND
329
+ [OK] OR from NAND
330
+ [OK] XOR from NAND
331
+ [OK] Half adder sum
332
+ [OK] Half adder carry
333
+ [OK] BitVec add 3+5=8
334
+ [OK] Tseitin preserves satisfiability
335
+ [OK] DPLL finds SAT
336
+ [OK] DPLL finds UNSAT
337
+ [OK] Unit propagation
338
+ [OK] Proof certificate valid
339
+ [OK] Checker accepts valid
340
+ [OK] Checker rejects invalid
341
+ [OK] Parse module
342
+ [OK] Elaborate module
343
+ [OK] NAND normal form
344
+ [OK] De Morgan via eval
345
+ [OK] MUX correctness
346
+
347
+ 20/20 tests passed.
348
+ ```
349
+
350
+ ---
351
+
352
+ ## Requirements
353
+
354
+ - GHC 8.10+ (Haskell compiler)
355
+ - Cabal 3.0+
356
+ - gfortran (for Fortran backend, optional)
357
+ - Zero external solver dependencies (no Z3, no MiniSat, no SMT-LIB)
358
+
359
+ ```bash
360
+ # Install GHC + Cabal (if needed)
361
+ curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
362
+
363
+ # Build and run
364
+ cabal build
365
+ cabal run pure-validity -- examples/gates.nf
366
+ cabal test
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Theory
372
+
373
+ The verification approach combines:
374
+
375
+ 1. **Tseitin transformation** β€” Boolean formula to CNF with linear blowup (not exponential)
376
+ 2. **DPLL** β€” systematic backtracking search with unit propagation
377
+ 3. **CDCL** β€” conflict-driven clause learning for exponential speedup on structured problems
378
+ 4. **Resolution proofs** β€” the solver records why it concluded UNSAT
379
+ 5. **Proof checking** β€” independent verification that each resolution step is valid
380
+
381
+ 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).
382
+
383
+ ---
384
+
385
+ <p align="center">
386
+ <b>Built by Ahmad Ali Parr + SnapKitty Collective</b>
387
+ </p>
388
+
389
+ <p align="center">
390
+
391
+ ```
392
+ ╔══════════════════════════════════════════════════════╗
393
+ β•‘ β•‘
394
+ β•‘ The engine searches. β•‘
395
+ β•‘ The kernel decides. β•‘
396
+ β•‘ β•‘
397
+ β•‘ If the kernel is correct, the system is sound. β•‘
398
+ β•‘ The kernel is 80 lines. β•‘
399
+ β•‘ Read them yourself. β•‘
400
+ β•‘ β•‘
401
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
402
+ ```
403
+
404
+ </p>
405
+
406
+ ---
407
+
408
+ ## License
409
+
410
+ Licensed under **AGPL-3.0** ([LICENSE](LICENSE)), with these additional license files:
411
+
412
+ - [LICENSE.tri](LICENSE.tri): SnapKitty Tri-License
413
+
414
+ ### πŸ’Ό Commercial License
415
+
416
+ Snapkitty code is free and open under **AGPL-3.0** for open-source use. Building a commercial product or service? A **proprietary commercial license** from Snapkitty Collective LLC lets you ship this code without the AGPL's source-sharing and network-use obligations.
417
+
418
+ **[β†’ Get a commercial license](mailto:A.parr@belespritdaccord.uk?subject=Commercial%20license:%20pure-validity)** Β· A.parr@belespritdaccord.uk