pqblocks-acvp
NIST ACVP conformance harness for FIPS 203 (ML-KEM) and FIPS 204 (ML-DSA), with a pure-Python reference oracle (kyber-py, dilithium-py) and partial adapters for pyca/cryptography (pure ML-DSA sigVer) and liboqs (ML-KEM decapsulation), plus a Go placeholder. Use it when evaluating and verifying post-quantum cryptography implementations against official NIST ACVP test corpora without denominator shrinkage. Standards implemented: NIST ACVP, FIPS 203 (ML-KEM), FIPS 204 (ML-DSA). SLH-DSA (FIPS 205) is not yet covered.
pip install git+https://github.com/PQBlocks/acvp-conformance
from pqblocks_acvp.runner import build_golden_session
from pqblocks_acvp.harness import ConformanceHarness
from pqblocks_acvp.adapters.reference import ReferencePQCAdapter
session = build_golden_session()
harness = ConformanceHarness([ReferencePQCAdapter()])
reports = harness.run_session(session)
rep = reports["Reference-FIPS-Oracle"]
print(f"Executed {rep.total_attempted} cases: {rep.passed} passed (denominator verified: {rep.denominator_verified})")
Why PQBlocks?
Most conformance testing scripts suffer from favorable-case attrition: when a target library lacks support for an algorithm or key format (such as Go crypto/mlkem lacking ML-KEM-512, or liboqs using internal randomness), tests are silently omitted or dropped from the denominator, inflating the reported pass rate.
pqblocks-acvp solves this with:
- 5-way outcome taxonomy: Every test case is categorized into exactly one of:
PASS,DOCUMENTED_VALIDATION_REJECTION,UNSUPPORTED_OPERATION,ADAPTER_INVOCATION_ERROR, orMISMATCH. - Strict Denominator Preservation: The total attempted cases must strictly equal the sum of all taxonomy buckets: $$\text{Attempted} = \text{Passed} + \text{DVR} + \text{Unsupported} + \text{Errors} + \text{Mismatches}$$
- Adapters: one
BasePQCAdapterinterface. An adapter that cannot consume an ACVP case (pyca's seed-only ML-KEM keys, liboqs' internal randomness) reports it asUNSUPPORTED_OPERATION. No key-format conversion is implemented. - Re-execution helper (
G7ReexecutionFramework): samples cases and compares two adapters' outcome categories. It has only been run against the Go placeholder (agreement 0.0).
Installation
pip install git+https://github.com/PQBlocks/acvp-conformance
Optional dependencies:
- For
pyca/cryptographyadapter:pip install "cryptography>=47.0.0" - For
liboqsadapter: systemliboqs.soandpip install liboqs-python
Usage
Command Line Interface
# Run built-in golden conformance test session
python -m pqblocks_acvp.runner --golden
# Output results as structured JSON
python -m pqblocks_acvp.runner --golden --json
# Run against an external NIST ACVP JSON test file
python -m pqblocks_acvp.runner --corpus /path/to/internalProjection.json
# Print the fixed reference-component licence list (SPDX 2.3-shaped, not a full SPDX document)
python -m pqblocks_acvp.runner --spdx
Python API
from pqblocks_acvp.parser import ACVPParser
from pqblocks_acvp.harness import ConformanceHarness
from pqblocks_acvp.adapters.reference import ReferencePQCAdapter
from pqblocks_acvp.adapters.go_bridge import GoBridgeAdapter
from pqblocks_acvp.adapters.pyca import PyCAAdapter
# Parse an official NIST ACVP session
session = ACVPParser.parse_file("tests/vectors/ML-KEM-encapDecap-FIPS203/internalProjection.json")
# Configure target adapters
adapters = [
ReferencePQCAdapter(),
GoBridgeAdapter(),
PyCAAdapter(),
]
# Run the test harness
harness = ConformanceHarness(adapters)
reports = harness.run_session(session)
for adapter_name, report in reports.items():
print(f"Adapter: {adapter_name}")
print(f" Total Attempted: {report.total_attempted}")
print(f" Passed: {report.passed}")
print(f" DVR: {report.documented_validation_rejections}")
print(f" Unsupported: {report.unsupported_operations}")
print(f" Mismatches: {report.mismatches}")
print(f" Denominator OK: {report.denominator_verified}")
API Reference
pqblocks_acvp.harness
ConformanceHarness(adapters: List[BasePQCAdapter]): Test orchestrator managing cross-implementation execution.run_session(session: ACVPTestSession) -> Dict[str, ConformanceReport]: Executes all test cases in the session across all configured adapters.run_case(test_case: TestCase) -> Dict[str, ExecutionResult]: Executes a single test case across all configured adapters.
ConformanceReport: Data class holding per-adapter metrics (total_attempted,passed,documented_validation_rejections,unsupported_operations,adapter_errors,mismatches,results)..denominator_verified -> bool: ReturnsTrueiftotal_attempted == passed + documented_validation_rejections + unsupported_operations + adapter_errors + mismatches..summary_dict() -> Dict[str, Any]: Serializes the report summary to a Python dictionary.
pqblocks_acvp.parser
ACVPParser: Static parser for NIST ACVP JSON vector files.parse_file(path: str) -> ACVPTestSession: Parses an ACVP JSON file from disk.parse_dict(data: Dict[str, Any]) -> ACVPTestSession: Parses an in-memory ACVP dictionary.
TestCase(tcId, function, parameter_set, inputs, expected): Represents an individual test case.TestGroup(tgId, algorithm, mode, parameter_set, function, test_type, test_cases): Represents a group of related test cases sharing common parameters.ACVPTestSession(vsId, algorithm, groups): Top-level container for an ACVP validation session.
pqblocks_acvp.taxonomy
TaxonomyCategory(Enum):PASS: Implementation output matches expected NIST vector bit-for-bit.DOCUMENTED_VALIDATION_REJECTION: Implementation correctly rejected malformed/invalid inputs per specification.UNSUPPORTED_OPERATION: Target library does not implement the requested algorithm, mode, or key format.ADAPTER_INVOCATION_ERROR: Communication, parsing, or runtime crash occurred.MISMATCH: Implementation completed execution but returned incorrect cryptographic output.
TaxonomyClassifier:classify(actual, expected, unsupported=False, validation_rejected=False, exit_code=0, error_msg="") -> TaxonomyCategory: Classifies a test execution outcome.
pqblocks_acvp.reference
MLKEMReferenceOracle:keygen(parameter_set: str, d_hex: str, z_hex: str) -> Tuple[str, str]: Generates(ek, dk)from 32-byte hex seedsdandz.encapsulate(parameter_set: str, ek_hex: str, m_hex: str) -> Tuple[str, str]: Produces(c, k)ciphertext and shared key from public keyekand 32-byte seedm.decapsulate(parameter_set: str, dk_hex: str, c_hex: str) -> str: Decapsulates ciphertextcusing expanded secret keydkto produce shared keyk.
MLDSAReferenceOracle:verify(parameter_set: str, pk_hex: str, msg_hex: str, sig_hex: str, ctx_hex: str = "") -> bool: Verifies an ML-DSA digital signature against public keypkand messagemsg.
pqblocks_acvp.adapters
BasePQCAdapter(name: str): Abstract base class for all target adapters.supports_algorithm(parameter_set: str, function: str) -> boolrun(test_case: TestCase) -> ExecutionResult
ReferencePQCAdapter: In-process reference oracle adapter (built onkyber-pyanddilithium-py).GoBridgeAdapter: placeholder for Gocrypto/mlkem. No Go program is called; every case is reportedUNSUPPORTED_OPERATION.PyCAAdapter: pyca/cryptography (≥ 47) ML-DSA external/pure signature verification; ML-KEM cases are reported unsupported.LibOQSAdapter: liboqs ML-KEM decapsulation only; encapsulation (no callerm) and ML-DSA are reported unsupported.
Limitations
-
Measured on the vendored corpus: on
ML-KEM-encapDecap-FIPS203(165 cases) the reference oracle gives 105 passed, 60 unsupported (key-check functions), 0 mismatches, 0 errors. The CLI text table has a Mismatch column;--jsongives the full summary. -
Not a Cryptographic Implementation:
pqblocks-acvpis a test harness and conformance validator; it is not designed to perform cryptographic encryption or signature operations in high-throughput production environments. -
Third-Party Runtime Dependencies: Testing external libraries (such as Go
crypto/mlkemor Cliboqs) requires those runtimes to be installed on the host system. When absent, the harness correctly records them asUNSUPPORTED_OPERATION. -
Validation Status:
pqblocks-acvpis self-verified against official NIST ACVP test vectors for FIPS 203 and FIPS 204 (SLH-DSA / FIPS 205 is not yet covered). It is not an accredited NVLAP laboratory report or CMVP validation certificate.
Security Notes
See SECURITY_NOTES.md for details on memory safety, input handling, and side-channel considerations.
Verification
Full verification evidence and test results are documented in:
Part of PQBlocks
pqblocks-acvp is part of the PQBlocks suite of post-quantum cryptographic primitives, tools, and verification engines.
License: Apache-2.0.
Metadata
Release files for pqblocks-acvp 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pqblocks_acvp-0.1.0.tar.gz | 28.8 kB | Without provenance | Details for pqblocks_acvp-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pqblocks_acvp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for pqblocks_acvp-0.1.0-py3-none-any.whl |
Total release size: 54.0 kB
Release files / pqblocks_acvp-0.1.0.tar.gz
| Download URL | pqblocks_acvp-0.1.0.tar.gz |
|---|---|
| Size | 28.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0e24e8049ed32f0b56edad5cfafd20043ed9a1711c9ba9869f456e99bda2f1bd
|
|
BLAKE2b-256 checksum How to use checksums |
2bfe03a2f6d1949d89248091102318450c2d76afeb92e9fa22b237be2554c921
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / pqblocks_acvp-0.1.0-py3-none-any.whl
| Download URL | pqblocks_acvp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
05db71b50fffd1f68325f5841619a1080e806deb8bf1d6b26f98877020b0fe33
|
|
BLAKE2b-256 checksum How to use checksums |
2190e101d9f076cc6ee60b9079b9361fee347a229cd2be763991e6ce6f0e3684
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for pqblocks-acvp 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.