pq-verify 2.6.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ {
2
+ "cells": [
3
+ {"cell_type":"markdown","metadata":{},"source":["# pq-verify v2.6.0 — One-Click Demo\n","\n","Run all cells (Runtime -> Run all). ~3 minutes to 240/240 NIST ACVP vectors.\n","\n","Upload `pq_verify_v2_6_0.py` when the file picker appears in Cell 2."]},
4
+ {"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# Cell 1: dependencies (~60s)\n","!apt-get install -y -qq coq gcc g++ > /dev/null 2>&1\n","!pip install kyber-py -q --break-system-packages\n","print('dependencies installed')"]},
5
+ {"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# Cell 2: upload + load the stack (runs 160-test self-suite)\n","from google.colab import files\n","up = files.upload()\n","fn = list(up.keys())[0]\n","exec(open(fn).read())"]},
6
+ {"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# Cell 3: full NIST ACVP — all 12 groups, 240/240\n","pqverify_acvp()"]},
7
+ {"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# Cell 4: parameter security check\n","pqverify_params('ML-KEM-1024')"]},
8
+ {"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# Cell 5: native full-KEM at Level 5\n","pqverify_kem(k=4)"]},
9
+ {"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# Cell 6: audit a compiled .so (build a demo NTT, then audit it)\n","ntt_c = '''#include <stdint.h>\n","#define Q 3329\n","#define N 256\n","static uint16_t pw(uint16_t b,uint32_t e,uint16_t q){uint32_t r=1,x=b;while(e){if(e&1)r=r*x%q;x=x*x%q;e>>=1;}return(uint16_t)r;}\n","static uint32_t br(uint32_t x){uint32_t r=0;for(int i=0;i<7;i++){r=(r<<1)|(x&1);x>>=1;}return r;}\n","static uint16_t z[128];static int rdy=0;\n","void ntt(uint16_t f[N]){if(!rdy){for(int i=0;i<128;i++)z[i]=pw(17,br(i),Q);rdy=1;}int k=1;\n","for(int L=128;L>=2;L>>=1)for(int s=0;s<N;s+=2*L){uint16_t zz=z[k++];for(int j=s;j<s+L;j++){\n","uint16_t t=(uint16_t)(((uint32_t)zz*f[j+L])%Q);f[j+L]=(uint16_t)((f[j]+Q-t)%Q);f[j]=(uint16_t)((f[j]+t)%Q);}}}'''\n","open('kyber_ntt.c','w').write(ntt_c)\n","import os; os.system('gcc -O3 -shared -fPIC -o libkyber_ntt.so kyber_ntt.c')\n","ntt = pqverify_load_so('./libkyber_ntt.so','ntt')\n","pqverify_kat(ntt, k=4)\n","pqverify_leakage()"]}
10
+ ],
11
+ "metadata":{"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python"}},
12
+ "nbformat":4,"nbformat_minor":0
13
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nicholas Maino (iamweare)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ include README.md
2
+ include LICENSE
3
+ include QUICKSTART.md
4
+ include DEMO.ipynb
5
+ include vendor_audit_template.py
6
+ include sample_report.json
7
+ recursive-include pq_verify/vectors *.json.gz *.json *.md
@@ -0,0 +1,231 @@
1
+ Metadata-Version: 2.4
2
+ Name: pq-verify
3
+ Version: 2.6.5
4
+ Summary: Independent verification for ML-KEM / ML-DSA implementations — native field NTT verification, NIST ACVP, lattice parameter security, Coq certificates.
5
+ Author-email: Nicholas Maino <maiknown@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/bigDSanalyst/pq-verify
8
+ Project-URL: Repository, https://github.com/bigDSanalyst/pq-verify
9
+ Project-URL: Zenodo DOI, https://doi.org/10.5281/zenodo.19302050
10
+ Keywords: post-quantum,cryptography,ML-KEM,ML-DSA,Kyber,Dilithium,FIPS-203,FIPS-204,NIST,ACVP,NTT,verification,lattice
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Topic :: Security :: Cryptography
17
+ Requires-Python: >=3.8
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Provides-Extra: full
21
+ Requires-Dist: kyber-py; extra == "full"
22
+ Requires-Dist: dilithium-py; extra == "full"
23
+ Requires-Dist: sympy; extra == "full"
24
+ Requires-Dist: slh-dsa; extra == "full"
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0; extra == "dev"
27
+ Requires-Dist: kyber-py; extra == "dev"
28
+ Requires-Dist: dilithium-py; extra == "dev"
29
+ Requires-Dist: sympy; extra == "dev"
30
+ Requires-Dist: slh-dsa; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # pq-verify v2.6.4 — PQC Implementation Verification
34
+
35
+ ![version](https://img.shields.io/badge/version-2.6.4-blue)
36
+ ![license](https://img.shields.io/badge/license-MIT-green)
37
+ ![tests](https://img.shields.io/badge/tests-160%2F160-brightgreen)
38
+ ![ACVP-KEM](https://img.shields.io/badge/ML--KEM%20ACVP-240%2F240-brightgreen)
39
+ ![ACVP-DSA](https://img.shields.io/badge/ML--DSA%20ACVP-615%2F615-brightgreen)
40
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21739511.svg)](https://doi.org/10.5281/zenodo.21739511)
41
+
42
+ **Independent verification for ML-KEM (Kyber) and ML-DSA (Dilithium) implementations.**
43
+
44
+ You deploy post-quantum cryptography. pq-verify proves your implementation computes the FIPS 203/204 standard correctly — in the native finite field, against NIST's own test vectors, with machine-checkable certificates. Plus FIPS 205 SLH-DSA parameter validation across all 12 parameter sets.
45
+
46
+ It does not compute PQC. It verifies the implementations that do: liboqs, BoringSSL, OpenSSL+OQS, HSM firmware, or your own code.
47
+
48
+ ---
49
+
50
+ ## What you get
51
+
52
+ A three-layer audit of any ML-KEM/ML-DSA implementation:
53
+
54
+ | Layer | Question answered | How |
55
+ |-------|-------------------|-----|
56
+ | **Correctness** | Does the NTT compute the FIPS definition? | Field-native verification + non-circular KAT |
57
+ | **Compliance** | Does it match NIST's published vectors? | ML-KEM 240/240 + ML-DSA 615/615 = 855/855 ACVP vectors (pinned) |
58
+ | **Security** | Are the parameters hard enough? | Bai-Galbraith primal-uSVP + hybrid attack estimator |
59
+
60
+ Plus per-layer side-channel leakage analysis with protection-allocation recommendations.
61
+
62
+ Every result is **reproducible** — deterministic output, SHA-256 fingerprint, re-runnable by your own auditors.
63
+
64
+ ---
65
+
66
+ ## Proven (all tested on commodity hardware, Google Colab CPU)
67
+
68
+ - **160/160** self-test across 6 field-native engines, 6 phases
69
+ - **240/240** NIST ACVP ML-KEM vectors — keyGen + encaps + decaps byte-exact, KeyCheck bool-exact
70
+ - **Native full-KEM** verified at ML-KEM-1024 (Level 5): recovery 20/20, negative control caught
71
+ - **Non-circular KAT** 100/100 against the independent FIPS reference
72
+ - Calibrated lattice estimator: reproduces lattice-estimator exactly (Kyber-512 β=406/118.6 bits)
73
+ - **Coq certificates** verified by `coqc` with real exit codes
74
+
75
+ ---
76
+
77
+ ## Quick start
78
+
79
+ Open `DEMO.ipynb` in Google Colab and run all cells. ~3 minutes to 855/855.
80
+
81
+ Or, in any Python 3.8+ environment with gcc:
82
+
83
+ ```python
84
+ exec(open('pq_verify_v2_6_1.py').read()) # 160-test self-suite + loads the API
85
+
86
+ pqverify_acvp() # full NIST ACVP, all parameter sets
87
+ pqverify_params('ML-KEM-1024') # parameter security check
88
+ pqverify_kem(k=4) # native full-KEM at Level 5
89
+ ```
90
+
91
+ To audit your own compiled library:
92
+
93
+ ```python
94
+ ntt = pqverify_load_so('/path/to/your_library.so', 'ntt_symbol')
95
+ pqverify_scan(ntt) # full audit + KAT + leakage
96
+ ```
97
+
98
+ See `vendor_audit_template.py` for the complete "give us your .so → get a JSON report" workflow.
99
+
100
+ ---
101
+
102
+ ## Public API
103
+
104
+ | Function | Purpose |
105
+ |----------|---------|
106
+ | `main()` | 160-test self-suite |
107
+ | `pqverify_acvp()` | Full NIST ACVP end-to-end ML-KEM (240/240, all groups) |
108
+ | `pqverify_mldsa_acvp()` | Full NIST ACVP end-to-end ML-DSA (615/615, FIPS 204) |
109
+ | `pqverify_slhdsa_acvp()` | NIST ACVP SLH-DSA keyGen (120/120, FIPS 205, all 12 parameter sets) |
110
+ | `pqverify_acvp_all()` | ML-KEM + ML-DSA (855/855) offline; `slhdsa=True` adds FIPS 205 → 975/975 |
111
+ | `pqverify_params(set)` | Parameter security: primal-uSVP + sparse hybrid |
112
+ | `pqverify_kem(k=4)` | Native algebraic full-KEM verification |
113
+ | `pqverify_kat(ntt, k=4)` | Non-circular KAT vs FIPS definition |
114
+ | `pqverify_load_so(path, sym)` | Load NTT from a compiled .so |
115
+ | `pqverify_scan(target)` | Auto-discover + audit NTT functions |
116
+ | `pqverify_leakage()` | Per-layer protection-allocation table |
117
+
118
+ ---
119
+
120
+ ## Deterministic by default
121
+
122
+ pq-verify ships with a **frozen, versioned snapshot of NIST's ACVP vectors** bundled
123
+ inside the package (gzipped, ~7 MB). By default it verifies against those — so:
124
+
125
+ - **the same input gives the same result, every run, forever**
126
+ - **it works with no network** — air-gapped, offline, no GitHub reachability needed
127
+ - **NIST editing their published files cannot change or break your result**
128
+
129
+ That last point is not hypothetical: NIST periodically regenerates these vectors and
130
+ has changed the ML-KEM `encapDecap` schema (the `keyFormat` seed/expanded split) more
131
+ than once. A tool that fetches live gives different answers on different days. This one
132
+ does not.
133
+
134
+ ```python
135
+ pqverify_acvp_all() # pinned bundle, offline, deterministic → 855/855
136
+ pqverify_acvp_all(live=True) # opt in: fetch NIST's current vectors instead
137
+ pqverify_acvp_all(vector_dir=d) # or point at your own local vector set
138
+ ```
139
+
140
+ Vector provenance and per-file sha256 are recorded in `pq_verify/vectors/MANIFEST.json`.
141
+ A scheduled GitHub Action watches upstream and opens an issue when NIST changes
142
+ something, so re-pinning is a deliberate, reviewed act rather than a live dependency.
143
+
144
+ ## Scope
145
+
146
+ pq-verify verifies the **algebraic substance** of ML-KEM/ML-DSA (NTT, module-LWE relations, parameter security) natively in Z₃₃₂₉ / Z₈₃₈₀₄₁₇. The **non-algebraic layers** (SHAKE/SHA3 hashing, sampling, compression, the FO transform) are bit/byte operations verified by NIST ACVP end-to-end testing, not native field solving.
147
+
148
+ The algebraic core is proven natively where the proof is exact; the full implementation is proven byte-exact against NIST's own bytes. We make the claims we can prove.
149
+
150
+ ---
151
+
152
+ ## What's in this package
153
+
154
+ ```
155
+ pq_verify/
156
+ __init__.py Public API (11 functions)
157
+ core.py The stack (~6,100 lines, 6 field-native engines)
158
+ cli.py Command-line interface
159
+ tests/test_pqverify.py 18-test pytest suite
160
+ pyproject.toml Build config + console-script entry point
161
+ dist/
162
+ pq_verify-2.6.4-py3-none-any.whl Installable wheel
163
+ pq_verify-2.6.4.tar.gz Source distribution
164
+ DEMO.ipynb One-click Colab demo → 855/855
165
+ vendor_audit_template.py Drop-in .so audit → JSON report
166
+ sample_report.json Example output (what your auditors receive)
167
+ README.md / QUICKSTART.md / LICENSE / CITATION.cff
168
+ ```
169
+
170
+ Install: `pip install dist/pq_verify-2.6.4-py3-none-any.whl`
171
+
172
+ ---
173
+
174
+ ## Requirements
175
+
176
+ **Minimum (core engines + ~149 self-tests):**
177
+ - Python 3.8+
178
+ - gcc and g++ (the C/C++ engines compile at runtime)
179
+
180
+ **For the full 160/160 self-suite and the 855/855 ACVP claim:**
181
+ - `kyber-py` — **required** for `pqverify_acvp()` (the byte-exact NIST reference) and the FIPS 203 roundtrip tests
182
+ - `dilithium-py` — **required** for `pqverify_mldsa_acvp()` (the 615 ML-DSA vectors)
183
+ - `coq` — required for the Coq certificate verification tests
184
+ - `sympy` — required for the Engine-6 Conjecture 7 exact-rational test (without it: 159/160)
185
+
186
+ ```bash
187
+ apt-get install -y coq gcc g++
188
+ pip install kyber-py dilithium-py sympy --break-system-packages
189
+ ```
190
+
191
+ **Optional (1 test each, everything works without them):**
192
+ - `cryptominisat` — the CMS5 speed-comparison benchmark
193
+ - `slh-dsa` — SLH-DSA live roundtrip (parameters still validate without it)
194
+ - network access — `pqverify_acvp()` fetches NIST vectors from GitHub live; for air-gapped use, pass `prompt_dir=` pointing at local vector files
195
+
196
+ **Deliberately NOT required** (a deployment advantage):
197
+ - No numpy, scipy, or PyTorch — pure Python + ctypes + inline C
198
+ - No SageMath — the `pqverify_params` lattice estimator is self-contained (it reproduces the lattice-estimator's results without it)
199
+
200
+ ---
201
+
202
+ ## License
203
+
204
+ MIT. The verifier is open-source — builds trust, enables adoption. Commercial support, custom engine development, and PQC audit engagements available separately.
205
+
206
+ ## Citing this software
207
+
208
+ Archived on Zenodo with a citable DOI:
209
+
210
+ > Maino, N. C. (2026). *pq-verify: Independent verification for ML-KEM / ML-DSA
211
+ > implementations* (v2.6.4). Zenodo. https://doi.org/10.5281/zenodo.21739511
212
+
213
+ ```bibtex
214
+ @software{maino_pqverify_2026,
215
+ author = {Maino, Nicholas Clifford},
216
+ title = {pq-verify: Independent verification for ML-KEM / ML-DSA implementations},
217
+ version = {2.6.4},
218
+ year = {2026},
219
+ publisher = {Zenodo},
220
+ doi = {10.5281/zenodo.21739511},
221
+ url = {https://doi.org/10.5281/zenodo.21739511}
222
+ }
223
+ ```
224
+
225
+ The DOI above resolves to this specific release. The companion paper is
226
+ [10.5281/zenodo.19302050](https://doi.org/10.5281/zenodo.19302050).
227
+
228
+ ## Contact
229
+
230
+ Nicholas Maino (iamweare) · maiknown@gmail.com · https://github.com/bigDSanalyst
231
+ Zenodo: https://doi.org/10.5281/zenodo.19302050
@@ -0,0 +1,85 @@
1
+ # pq-verify v2.6.0 — Quickstart
2
+
3
+ ## 1. Run the self-test (confirms the tool works on your machine)
4
+
5
+ Google Colab, or any Linux with `gcc` + Python 3.8+:
6
+
7
+ ```bash
8
+ apt-get install -y coq && pip install kyber-py dilithium-py sympy # for full 160/160 + 885/885
9
+ ```
10
+
11
+ ```python
12
+ exec(open('pq_verify_v2_6_1.py').read())
13
+ ```
14
+
15
+ Expected: a 7-phase report ending in `OVERALL: 160/160 tests passed`.
16
+ Without coq/kyber-py/sympy you'll see fewer (those tests report as failures, not skips).
17
+
18
+ After loading, eight public functions are available: `main`, `pqverify_acvp`,
19
+ `pqverify_params`, `pqverify_kem`, `pqverify_kat`, `pqverify_load_so`,
20
+ `pqverify_scan`, and `pqverify_leakage`.
21
+
22
+ ## 2. Verify your own implementation
23
+
24
+ ### Option A — you have a compiled .so
25
+
26
+ Edit the CONFIG block in `vendor_audit_template.py`:
27
+
28
+ ```python
29
+ SO_PATH = "/path/to/your_library.so"
30
+ NTT_SYMBOL = "ntt" # see "find your symbol" below
31
+ ALGORITHM = "ML-KEM-1024" # or ML-KEM-512/768, ML-DSA-44/65/87
32
+ ```
33
+
34
+ Then:
35
+
36
+ ```python
37
+ exec(open('pq_verify_v2_6_1.py').read()) # load the engine
38
+ exec(open('vendor_audit_template.py').read()) # runs the audit
39
+ ```
40
+
41
+ Output: console report + `pqverify_vendor_report.json` (machine-readable,
42
+ with a reproducible SHA-256 fingerprint).
43
+
44
+ ### Find your symbol (if you don't know it)
45
+
46
+ ```python
47
+ discover_symbols("/path/to/your_library.so")
48
+ ```
49
+
50
+ Lists exported NTT symbols. Note: many libraries inline the NTT as a
51
+ `static` function, so it won't be exported — in that case a small dedicated
52
+ `.so` exposing `void ntt(int16_t[256])` is the cleanest path.
53
+
54
+ ### Option B — you have a Python implementation
55
+
56
+ ```python
57
+ exec(open('pq_verify_v2_6_1.py').read())
58
+ # your_ntt(list[int]) -> list[int] defined in this session
59
+ pqverify_scan(globals()) # auto-discovers and audits it
60
+ ```
61
+
62
+ ## 3. Individual checks
63
+
64
+ ```python
65
+ pqverify_kem(k=4) # native full-KEM, ML-KEM-1024 / Level 5
66
+ pqverify_kat(your_ntt, k=4) # non-circular KAT vs FIPS definition
67
+ pqverify_leakage() # per-layer protection-allocation table
68
+ ```
69
+
70
+ `k` selects the security level: 2 → Level 1, 3 → Level 3, 4 → Level 5
71
+ (Dilithium: 4/6/8 with `family='dilithium', q=8380417, zeta=1753`).
72
+
73
+ ## 4. Reproducibility
74
+
75
+ The report is deterministic: same input → identical output → identical
76
+ SHA-256 fingerprint. Re-run any audit and compare fingerprints to confirm
77
+ the result wasn't tampered with.
78
+
79
+ ## Notes
80
+
81
+ - Free Colab sessions are per-tab and reset after ~90 min idle. Keep the
82
+ `.py` files in Google Drive and `exec()` them from there to avoid re-uploading.
83
+ - Engines compile at runtime via gcc/g++ — first run takes a few seconds.
84
+ - Never install torchtext in the same Colab environment (unrelated, but it
85
+ corrupts the runtime).
@@ -0,0 +1,199 @@
1
+ # pq-verify v2.6.4 — PQC Implementation Verification
2
+
3
+ ![version](https://img.shields.io/badge/version-2.6.4-blue)
4
+ ![license](https://img.shields.io/badge/license-MIT-green)
5
+ ![tests](https://img.shields.io/badge/tests-160%2F160-brightgreen)
6
+ ![ACVP-KEM](https://img.shields.io/badge/ML--KEM%20ACVP-240%2F240-brightgreen)
7
+ ![ACVP-DSA](https://img.shields.io/badge/ML--DSA%20ACVP-615%2F615-brightgreen)
8
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21739511.svg)](https://doi.org/10.5281/zenodo.21739511)
9
+
10
+ **Independent verification for ML-KEM (Kyber) and ML-DSA (Dilithium) implementations.**
11
+
12
+ You deploy post-quantum cryptography. pq-verify proves your implementation computes the FIPS 203/204 standard correctly — in the native finite field, against NIST's own test vectors, with machine-checkable certificates. Plus FIPS 205 SLH-DSA parameter validation across all 12 parameter sets.
13
+
14
+ It does not compute PQC. It verifies the implementations that do: liboqs, BoringSSL, OpenSSL+OQS, HSM firmware, or your own code.
15
+
16
+ ---
17
+
18
+ ## What you get
19
+
20
+ A three-layer audit of any ML-KEM/ML-DSA implementation:
21
+
22
+ | Layer | Question answered | How |
23
+ |-------|-------------------|-----|
24
+ | **Correctness** | Does the NTT compute the FIPS definition? | Field-native verification + non-circular KAT |
25
+ | **Compliance** | Does it match NIST's published vectors? | ML-KEM 240/240 + ML-DSA 615/615 = 855/855 ACVP vectors (pinned) |
26
+ | **Security** | Are the parameters hard enough? | Bai-Galbraith primal-uSVP + hybrid attack estimator |
27
+
28
+ Plus per-layer side-channel leakage analysis with protection-allocation recommendations.
29
+
30
+ Every result is **reproducible** — deterministic output, SHA-256 fingerprint, re-runnable by your own auditors.
31
+
32
+ ---
33
+
34
+ ## Proven (all tested on commodity hardware, Google Colab CPU)
35
+
36
+ - **160/160** self-test across 6 field-native engines, 6 phases
37
+ - **240/240** NIST ACVP ML-KEM vectors — keyGen + encaps + decaps byte-exact, KeyCheck bool-exact
38
+ - **Native full-KEM** verified at ML-KEM-1024 (Level 5): recovery 20/20, negative control caught
39
+ - **Non-circular KAT** 100/100 against the independent FIPS reference
40
+ - Calibrated lattice estimator: reproduces lattice-estimator exactly (Kyber-512 β=406/118.6 bits)
41
+ - **Coq certificates** verified by `coqc` with real exit codes
42
+
43
+ ---
44
+
45
+ ## Quick start
46
+
47
+ Open `DEMO.ipynb` in Google Colab and run all cells. ~3 minutes to 855/855.
48
+
49
+ Or, in any Python 3.8+ environment with gcc:
50
+
51
+ ```python
52
+ exec(open('pq_verify_v2_6_1.py').read()) # 160-test self-suite + loads the API
53
+
54
+ pqverify_acvp() # full NIST ACVP, all parameter sets
55
+ pqverify_params('ML-KEM-1024') # parameter security check
56
+ pqverify_kem(k=4) # native full-KEM at Level 5
57
+ ```
58
+
59
+ To audit your own compiled library:
60
+
61
+ ```python
62
+ ntt = pqverify_load_so('/path/to/your_library.so', 'ntt_symbol')
63
+ pqverify_scan(ntt) # full audit + KAT + leakage
64
+ ```
65
+
66
+ See `vendor_audit_template.py` for the complete "give us your .so → get a JSON report" workflow.
67
+
68
+ ---
69
+
70
+ ## Public API
71
+
72
+ | Function | Purpose |
73
+ |----------|---------|
74
+ | `main()` | 160-test self-suite |
75
+ | `pqverify_acvp()` | Full NIST ACVP end-to-end ML-KEM (240/240, all groups) |
76
+ | `pqverify_mldsa_acvp()` | Full NIST ACVP end-to-end ML-DSA (615/615, FIPS 204) |
77
+ | `pqverify_slhdsa_acvp()` | NIST ACVP SLH-DSA keyGen (120/120, FIPS 205, all 12 parameter sets) |
78
+ | `pqverify_acvp_all()` | ML-KEM + ML-DSA (855/855) offline; `slhdsa=True` adds FIPS 205 → 975/975 |
79
+ | `pqverify_params(set)` | Parameter security: primal-uSVP + sparse hybrid |
80
+ | `pqverify_kem(k=4)` | Native algebraic full-KEM verification |
81
+ | `pqverify_kat(ntt, k=4)` | Non-circular KAT vs FIPS definition |
82
+ | `pqverify_load_so(path, sym)` | Load NTT from a compiled .so |
83
+ | `pqverify_scan(target)` | Auto-discover + audit NTT functions |
84
+ | `pqverify_leakage()` | Per-layer protection-allocation table |
85
+
86
+ ---
87
+
88
+ ## Deterministic by default
89
+
90
+ pq-verify ships with a **frozen, versioned snapshot of NIST's ACVP vectors** bundled
91
+ inside the package (gzipped, ~7 MB). By default it verifies against those — so:
92
+
93
+ - **the same input gives the same result, every run, forever**
94
+ - **it works with no network** — air-gapped, offline, no GitHub reachability needed
95
+ - **NIST editing their published files cannot change or break your result**
96
+
97
+ That last point is not hypothetical: NIST periodically regenerates these vectors and
98
+ has changed the ML-KEM `encapDecap` schema (the `keyFormat` seed/expanded split) more
99
+ than once. A tool that fetches live gives different answers on different days. This one
100
+ does not.
101
+
102
+ ```python
103
+ pqverify_acvp_all() # pinned bundle, offline, deterministic → 855/855
104
+ pqverify_acvp_all(live=True) # opt in: fetch NIST's current vectors instead
105
+ pqverify_acvp_all(vector_dir=d) # or point at your own local vector set
106
+ ```
107
+
108
+ Vector provenance and per-file sha256 are recorded in `pq_verify/vectors/MANIFEST.json`.
109
+ A scheduled GitHub Action watches upstream and opens an issue when NIST changes
110
+ something, so re-pinning is a deliberate, reviewed act rather than a live dependency.
111
+
112
+ ## Scope
113
+
114
+ pq-verify verifies the **algebraic substance** of ML-KEM/ML-DSA (NTT, module-LWE relations, parameter security) natively in Z₃₃₂₉ / Z₈₃₈₀₄₁₇. The **non-algebraic layers** (SHAKE/SHA3 hashing, sampling, compression, the FO transform) are bit/byte operations verified by NIST ACVP end-to-end testing, not native field solving.
115
+
116
+ The algebraic core is proven natively where the proof is exact; the full implementation is proven byte-exact against NIST's own bytes. We make the claims we can prove.
117
+
118
+ ---
119
+
120
+ ## What's in this package
121
+
122
+ ```
123
+ pq_verify/
124
+ __init__.py Public API (11 functions)
125
+ core.py The stack (~6,100 lines, 6 field-native engines)
126
+ cli.py Command-line interface
127
+ tests/test_pqverify.py 18-test pytest suite
128
+ pyproject.toml Build config + console-script entry point
129
+ dist/
130
+ pq_verify-2.6.4-py3-none-any.whl Installable wheel
131
+ pq_verify-2.6.4.tar.gz Source distribution
132
+ DEMO.ipynb One-click Colab demo → 855/855
133
+ vendor_audit_template.py Drop-in .so audit → JSON report
134
+ sample_report.json Example output (what your auditors receive)
135
+ README.md / QUICKSTART.md / LICENSE / CITATION.cff
136
+ ```
137
+
138
+ Install: `pip install dist/pq_verify-2.6.4-py3-none-any.whl`
139
+
140
+ ---
141
+
142
+ ## Requirements
143
+
144
+ **Minimum (core engines + ~149 self-tests):**
145
+ - Python 3.8+
146
+ - gcc and g++ (the C/C++ engines compile at runtime)
147
+
148
+ **For the full 160/160 self-suite and the 855/855 ACVP claim:**
149
+ - `kyber-py` — **required** for `pqverify_acvp()` (the byte-exact NIST reference) and the FIPS 203 roundtrip tests
150
+ - `dilithium-py` — **required** for `pqverify_mldsa_acvp()` (the 615 ML-DSA vectors)
151
+ - `coq` — required for the Coq certificate verification tests
152
+ - `sympy` — required for the Engine-6 Conjecture 7 exact-rational test (without it: 159/160)
153
+
154
+ ```bash
155
+ apt-get install -y coq gcc g++
156
+ pip install kyber-py dilithium-py sympy --break-system-packages
157
+ ```
158
+
159
+ **Optional (1 test each, everything works without them):**
160
+ - `cryptominisat` — the CMS5 speed-comparison benchmark
161
+ - `slh-dsa` — SLH-DSA live roundtrip (parameters still validate without it)
162
+ - network access — `pqverify_acvp()` fetches NIST vectors from GitHub live; for air-gapped use, pass `prompt_dir=` pointing at local vector files
163
+
164
+ **Deliberately NOT required** (a deployment advantage):
165
+ - No numpy, scipy, or PyTorch — pure Python + ctypes + inline C
166
+ - No SageMath — the `pqverify_params` lattice estimator is self-contained (it reproduces the lattice-estimator's results without it)
167
+
168
+ ---
169
+
170
+ ## License
171
+
172
+ MIT. The verifier is open-source — builds trust, enables adoption. Commercial support, custom engine development, and PQC audit engagements available separately.
173
+
174
+ ## Citing this software
175
+
176
+ Archived on Zenodo with a citable DOI:
177
+
178
+ > Maino, N. C. (2026). *pq-verify: Independent verification for ML-KEM / ML-DSA
179
+ > implementations* (v2.6.4). Zenodo. https://doi.org/10.5281/zenodo.21739511
180
+
181
+ ```bibtex
182
+ @software{maino_pqverify_2026,
183
+ author = {Maino, Nicholas Clifford},
184
+ title = {pq-verify: Independent verification for ML-KEM / ML-DSA implementations},
185
+ version = {2.6.4},
186
+ year = {2026},
187
+ publisher = {Zenodo},
188
+ doi = {10.5281/zenodo.21739511},
189
+ url = {https://doi.org/10.5281/zenodo.21739511}
190
+ }
191
+ ```
192
+
193
+ The DOI above resolves to this specific release. The companion paper is
194
+ [10.5281/zenodo.19302050](https://doi.org/10.5281/zenodo.19302050).
195
+
196
+ ## Contact
197
+
198
+ Nicholas Maino (iamweare) · maiknown@gmail.com · https://github.com/bigDSanalyst
199
+ Zenodo: https://doi.org/10.5281/zenodo.19302050
@@ -0,0 +1,54 @@
1
+ """
2
+ pq-verify — Independent verification for ML-KEM / ML-DSA implementations.
3
+
4
+ Verifies that post-quantum cryptography implementations compute the
5
+ FIPS 203/204 standard correctly: native field-native NTT verification,
6
+ non-circular Known Answer Tests, NIST ACVP end-to-end (270/270), a
7
+ Bai-Galbraith lattice parameter-security estimator, and per-layer
8
+ side-channel leakage analysis. Coq-certified, reproducible.
9
+
10
+ Author: Nicholas Maino (iamweare) — Melbourne AU
11
+ License: MIT
12
+ """
13
+
14
+ __version__ = "2.6.5"
15
+ __author__ = "Nicholas Maino (iamweare)"
16
+ __license__ = "MIT"
17
+
18
+ # Re-export the public API from the core engine (the real 5451-line stack).
19
+ from .core import (
20
+ main,
21
+ pqverify_kat,
22
+ pqverify_kem,
23
+ pqverify_acvp,
24
+ pqverify_mldsa_acvp,
25
+ pqverify_slhdsa_acvp,
26
+ pqverify_acvp_all,
27
+ pqverify_params,
28
+ pqverify_leakage,
29
+ pqverify_load_so,
30
+ pqverify_scan,
31
+ )
32
+
33
+ # FIPS 203 input-validation oracles (used by ACVP KeyCheck groups)
34
+ try:
35
+ from .core import check_encapsulation_key, check_decapsulation_key
36
+ except ImportError:
37
+ pass
38
+
39
+ __all__ = [
40
+ "__version__",
41
+ "main",
42
+ "pqverify_kat",
43
+ "pqverify_kem",
44
+ "pqverify_acvp",
45
+ "pqverify_mldsa_acvp",
46
+ "pqverify_slhdsa_acvp",
47
+ "pqverify_acvp_all",
48
+ "pqverify_params",
49
+ "pqverify_leakage",
50
+ "pqverify_load_so",
51
+ "pqverify_scan",
52
+ "check_encapsulation_key",
53
+ "check_decapsulation_key",
54
+ ]