feat(pqc): add device-resident DR0 and DR1 graphs - #8
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces the first two device-resident PQC milestones in phoenix_sdr_dsp.pqc: DR0 (native ML-DSA polynomial product) and DR1 (bounded SHAKE128 producer feeding ML-DSA-44 ExpandA rejection-sampling / RejNTT), with host-side ABIs, fail-closed native runners, contract tests, and validation/provenance documentation.
Changes:
- Add DR0: fail-closed Python IRON graph + production-local C++ kernel + production-local M33a arithmetic header and stable host ABI/oracle.
- Add DR1: stable ABI + fail-closed two-worker IRON graph + production-local Keccak/SHAKE producer and RejNTT sampler kernels.
- Add host-only/static contract tests, off-hardware harness/oracles, and detailed design + physical validation records for both milestones.
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_pqc_dr1_contract.py |
Static contracts asserting DR1 ABI, topology invariants, and documentation/record anchoring. |
tests/test_pqc_device_residency_contract.py |
Static contracts for DR0 ABI/topology plus kernel/source invariants and validation-record anchoring. |
tests/pqc_device_resident/test_m33_product_dr0.py |
DR0 off-hardware oracle tests plus a native-only physical gate runner. |
tests/pqc_device_resident/test_dr1_mldsa44_rejntt.py |
DR1 off-hardware compiled-kernel harness and oracle comparisons, plus malformed/corruption cases. |
tests/pqc_device_resident/dr1_reference.py |
Independent hashlib-based DR1 oracle (no production imports) for exact-output comparisons. |
tests/pqc_device_resident/__init__.py |
Declares the physical-device gate test package. |
phoenix_sdr_dsp/pqc/m33_product_graph.py |
DR0 fail-closed native IRON runner (2 ingress, 1 terminal egress). |
phoenix_sdr_dsp/pqc/kernels/m33a_arithmetic.hpp |
Production-local M33a NTT/basemul/INTT arithmetic + constants/zeta table. |
phoenix_sdr_dsp/pqc/kernels/m33_product_graph.cc |
DR0 AIE kernel implementing fused NTT/basemul/INTT and canonicalization. |
phoenix_sdr_dsp/pqc/kernels/dr1_shake128_service.cc |
DR1 incremental SHAKE128 producer with core-local state and fixed 8-token schedule. |
phoenix_sdr_dsp/pqc/kernels/dr1_mldsa44_rejntt.cc |
DR1 RejNTT sampler consuming 8 tokens and emitting one terminal result record. |
phoenix_sdr_dsp/pqc/kernels/dr1_keccak_f1600.hpp |
Production-local Keccak-f[1600] permutation tailored for DR1 SHAKE128 use. |
phoenix_sdr_dsp/pqc/dr1_mldsa44_rejntt_graph.py |
DR1 fail-closed two-worker IRON graph (2 host ingresses, 1 internal FIFO, 1 terminal result). |
phoenix_sdr_dsp/pqc/dr1_abi.py |
DR1 fixed ABI: request validation, descriptor build, sentinel creation, terminal parse/validation. |
phoenix_sdr_dsp/pqc/abi.py |
DR0 stable ABI and independent O(n²) negacyclic-product oracle + input validation. |
phoenix_sdr_dsp/pqc/__init__.py |
Exposes DR0 entry points and constants at the package level. |
docs/PQC_DR1_SILICON_VALIDATION_PENDING.md |
DR1 physical validation record and incident history/evidence details. |
docs/PQC_DR1_DESIGN.md |
DR1 design, ABI, bounded behavior, and claim boundary documentation. |
docs/PQC_DR0_SILICON_VALIDATION_20260817.md |
DR0 physical validation record (evidence boundary + results). |
docs/PQC_DR0_PROVENANCE.md |
DR0 provenance/adaptation record and audit boundary. |
docs/PQC_DR0_DESIGN.md |
DR0 design, ABI/topology invariants, failure behavior, and claim boundary. |
Suppressed comments (1)
phoenix_sdr_dsp/pqc/m33_product_graph.py:168
- Avoid hard-coding the modulus in the output canonicality check; using the shared ABI constant prevents the validation logic from silently diverging from the declared ABI.
if any(value < 0 or value >= 8_380_417 for value in result):
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+76
to
+90
| static void reject_candidate(uint8_t b0, uint8_t b1, uint8_t b2) { | ||
| const uint32_t z = (static_cast<uint32_t>(b0) | | ||
| (static_cast<uint32_t>(b1) << 8) | | ||
| (static_cast<uint32_t>(b2) << 16)) & 0x7fffffU; | ||
| if (z < kQ && g_sampler.accepted < kN) g_sampler.coefficient[g_sampler.accepted++] = static_cast<int32_t>(z); | ||
| } | ||
|
|
||
| static void consume_data(const uint8_t *data, uint16_t bytes_valid) { | ||
| DR1_SAMPLER_DISABLE_LOOP_UNROLL | ||
| for (uint16_t index = 0; index < bytes_valid; ++index) { | ||
| if (g_sampler.tail_len < 2) { | ||
| g_sampler.triple_tail[g_sampler.tail_len++] = data[index]; | ||
| } else { | ||
| reject_candidate(g_sampler.triple_tail[0], g_sampler.triple_tail[1], data[index]); | ||
| g_sampler.tail_len = 0; |
|
|
||
| import numpy as np | ||
|
|
||
| from .abi import POLYNOMIAL_BYTES, N, reference_negacyclic_product, validate_polynomial |
Comment on lines
+213
to
+218
| cls.library = ctypes.CDLL(str(library)) | ||
| cls.rho_type = ctypes.c_uint8 * abi.RHO_BYTES | ||
| cls.descriptor_type = ctypes.c_uint8 * abi.DESCRIPTOR_BYTES | ||
| cls.block_type = ctypes.c_uint8 * abi.XOF_BLOCK_BYTES | ||
| cls.result_type = ctypes.c_uint8 * abi.RESULT_BYTES | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the first two device-residency milestones for the PQC path:
Neither path has a host reference fallback. Intermediate NTT, SHAKE, and sampling state remains on the NPU; only the terminal result returns to the CPU.
Type of change
Silicon impact
python run_all_silicon_tests.pystill passes 12/12 bit-accurateThe canonical
run_all_silicon_tests.pyfile is intentionally unchanged (SHA-256742591321AC5DC3069A51DED4E198905367F8DC6261DF8C3EBAE20B5E333FBAD). DR0 and DR1 remain separate physical gates rather than being added to that runner.Physical evidence:
m33-dr0:silicon,TOTAL 24/24 PASS; log SHA-256678F1116813F38B1356518FD601060934D8C2D5682C935FFDAD5364E0AD6CA48.dr1-mldsa44-expanda-rejntt:silicon,TOTAL 33/33 PASS; 8,448 exact coefficient comparisons; log SHA-25685B373B1E3B8A1BD883DA6BBDE73F874EE5C331B4AE419E5D161758A64EB4A7E.(0,2)has 6,608 B.text; core(0,3)has 3,328 B.text.Host validation
The clean Windows zero-skip host log has SHA-256
2621EF2E4130003895A9DA46042CEAA232D9C11AA5D24A25D0800978283B9568.Additional gate:
Scope limits
Checklist
ruff checkpasses