Skip to content

feat(pqc): add device-resident DR0 and DR1 graphs - #8

Merged
midhatn merged 2 commits into
mainfrom
feat/pqc-device-residency-dr0-dr1
Aug 17, 2026
Merged

feat(pqc): add device-resident DR0 and DR1 graphs#8
midhatn merged 2 commits into
mainfrom
feat/pqc-device-residency-dr0-dr1

Conversation

@midhatn

@midhatn midhatn commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the first two device-residency milestones for the PQC path:

  • DR0: a native, device-resident ML-DSA polynomial product with exactly two host ingress FIFOs and one terminal egress.
  • DR1: a bounded incremental SHAKE128 service feeding ML-DSA-44 ExpandA rejection sampling and NTT, with one internal FIFO and one terminal result.
  • Fixed ABIs, fail-closed native runners, independent references, production-kernel harnesses, contract tests, provenance, and physical-validation records.

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

  • Bug fix (non-breaking)
  • New feature (non-breaking)
  • Breaking change
  • Documentation only
  • Toolchain / CI / infrastructure

Silicon impact

  • Full regression python run_all_silicon_tests.py still passes 12/12 bit-accurate
  • N/A — no kernel or host-runtime changes

The canonical run_all_silicon_tests.py file is intentionally unchanged (SHA-256 742591321AC5DC3069A51DED4E198905367F8DC6261DF8C3EBAE20B5E333FBAD). DR0 and DR1 remain separate physical gates rather than being added to that runner.

Physical evidence:

  • DR0: m33-dr0:silicon, TOTAL 24/24 PASS; log SHA-256 678F1116813F38B1356518FD601060934D8C2D5682C935FFDAD5364E0AD6CA48.
  • DR1: dr1-mldsa44-expanda-rejntt:silicon, TOTAL 33/33 PASS; 8,448 exact coefficient comparisons; log SHA-256 85B373B1E3B8A1BD883DA6BBDE73F874EE5C331B4AE419E5D161758A64EB4A7E.
  • DR1 worker ELFs fit the 16 KiB program-memory limit: core (0,2) has 6,608 B .text; core (0,3) has 3,328 B .text.

Host validation

python -m unittest \
  tests.test_pqc_dr1_contract \
  tests.pqc_device_resident.test_dr1_mldsa44_rejntt \
  tests.test_pqc_device_residency_contract \
  tests.pqc_device_resident.test_m33_product_dr0 \
  tests.test_m33_native_runner_contract \
  tests.test_regression_validation \
  -v

Ran 56 tests
OK

The clean Windows zero-skip host log has SHA-256 2621EF2E4130003895A9DA46042CEAA232D9C11AA5D24A25D0800978283B9568.

Additional gate:

ruff check phoenix_sdr_dsp/pqc tests/pqc_device_resident \
  tests/test_pqc_device_residency_contract.py tests/test_pqc_dr1_contract.py

All checks passed!

Scope limits

  • This does not claim complete FIPS 203/FIPS 204 operation residency.
  • DR1 physical testing covers the successful 33-case corpus. Malformed descriptors, token corruption, reset behavior, and bounded-limit behavior are covered by compiled production-kernel and contract tests.
  • No performance, constant-time, zeroization, conformance, or CMVP claim is made.

Checklist

  • Code follows the existing style; targeted ruff check passes
  • Relevant design, provenance, and validation documentation is included
  • Toolchain requirements are unchanged
  • Tests were added for ABIs, references, production kernels, and residency contracts
  • Commit message is descriptive

Copilot AI lite review requested due to automatic review settings August 17, 2026 17:33
@midhatn
midhatn merged commit 7b38973 into main Aug 17, 2026
5 checks passed
@midhatn
midhatn deleted the feat/pqc-device-residency-dr0-dr1 branch August 17, 2026 17:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants