PQ Provider Options Design

Audience: Security Guild, Scanner/Policy/Attestor engineers, crypto maintainers. Scope: The current shape of the post-quantum signing provider (pq.soft) — supported algorithms, activation gate, options, key handling, and the gap between design intent and what is implemented today.

Last updated: 2026-05-30 · Owners: Security Guild · Scanner Guild · Policy Guild

Reconciled against the implementation on 2026-05-30. The post-quantum signing provider is implemented as the pq.softcrypto plugin (StellaOps.Cryptography.Plugin.PqSoft), a software-only provider built on BouncyCastle PQC primitives. Several items in earlier drafts of this design (a Crypto:Providers appsettings registry, per-feature SigningProvider overrides, BLAKE3 hashing, PEM key files, liboqs/oqs-provider bindings) were never implemented; they are now marked NOT IMPLEMENTED or Draft / roadmap below rather than described as current behavior.

Goals

Provider implementation (current)

The PQ provider is a single ICryptoProvider implementation:

There is no separate pq-dilithium3 / pq-falcon512 provider. Earlier drafts named two distinct providers; in the implementation there is one provider (pq.soft) that supports two signature algorithms, selected per key.

Supported algorithms

PqSoftCryptoProvider.Supports(...) returns true only for the Signing/Verification capabilities and only for these two algorithm identifiers (from StellaOps.Cryptography.SignatureAlgorithms):

Algorithm id (constant)Literal valueBouncyCastle primitive
SignatureAlgorithms.Dilithium3DILITHIUM3MLDsaParameters.ml_dsa_65 (FIPS 204 ML-DSA-65), MLDsaSigner(deterministic: true)
SignatureAlgorithms.Falcon512FALCON512FalconParameters.falcon_512, FalconSigner

Notes:

Inconsistency to be aware of — the crypto plugin manifest (devops/etc/crypto-plugins-manifest.json, id pq.soft) advertises a broader capability set (ML-DSA-44/65/87, SLH-DSA-SHA2/SHAKE, SHA3-256/512, SHAKE256; compliance NIST-PQC, FIPS-203, FIPS-205). Those manifest capabilities are aspirational/inaccurate: the code only accepts DILITHIUM3 and FALCON512 for signing, supports no hashing, and provides no SLH-DSA / SHA3 implementation. Treat the C# Supports(...) result as ground truth, not the manifest capability strings.

Activation gate

PQ signing is gated off by default. The provider is enabled only when:

When the gate is closed, Supports(...) returns false for all algorithms and GetSigner / UpsertSigningKey throw InvalidOperationException ("Provider 'pq.soft' is disabled. Set PQ_SOFT_ALLOWED=1 or disable RequireEnvironmentGate to enable.").

Provider options (current shape)

The provider binds PqSoftProviderOptions:

{
  // PqSoftProviderOptions
  "RequireEnvironmentGate": true,        // default; gate via PQ_SOFT_ALLOWED
  "Keys": [
    {
      // PqSoftKeyOptions
      "KeyId": "pq-key-1",
      "Algorithm": "DILITHIUM3",          // or "FALCON512"; default DILITHIUM3
      "PrivateKeyPath": "secrets/pq/dilithium3.key",
      "PublicKeyPath": "secrets/pq/dilithium3.pub"   // optional
    }
  ]
}

There is no top-level Crypto.DefaultProvider / Crypto.Providers registry binding, no Type: "PostQuantum" discriminator, no Hash field, no CertPath, and no UseBlake3 field in the implementation. The only options bound by the PQ provider are RequireEnvironmentGate and a Keys list of PqSoftKeyOptions (KeyId, Algorithm, PrivateKeyPath, PublicKeyPath). Plugin discovery and priority (priority 70) come from the manifest entry, not from a Crypto appsettings section.

Key handling (current)

Selection rules

NOT IMPLEMENTED (Draft / roadmap). The following per-feature override keys referenced in earlier drafts do not exist anywhere in the codebase and are not consumed by Scanner, Policy, or Attestor:

  • Crypto:DefaultProvider
  • DSSE:SigningProvider
  • PolicyEngine:SigningProvider
  • Scanner:SigningProvider

There is likewise no “fall back to DefaultProvider and emit a warning” behavior for a missing PQ provider; a missing/unregistered key throws KeyNotFoundException and a closed gate throws InvalidOperationException.

Hash strategy

NOT IMPLEMENTED (Draft / roadmap). The PQ provider does not expose any hasher (GetHasher throws NotSupportedException). There is no UseBlake3 flag and no DeterministicHashVersion setting in the implementation; searches across src/** return no matches for either. Hashing for DSSE/attestation payloads continues to use the platform’s existing hash strategy (SHA-256), independent of the PQ signing provider. BLAKE3 selection and a DeterministicHashVersion = 2 switch are aspirational only.

Key formats

Corrected. PQ keys are not stored as PEM (BEGIN PUBLIC KEY / BEGIN PRIVATE KEY) and there is no liboqs / OpenQuantumSafe toolchain dependency. The implementation uses BouncyCastle (Org.BouncyCastle.*, Pqc.Crypto.Falcon, ML-DSA) and reads keys as raw bytes via File.ReadAllBytes. Private-key bytes act as deterministic seed material for key-pair generation (see “Key handling” above). The provider validates that a key’s stored algorithm matches the requested algorithm at sign time.

Testing plan

Implemented tests:

Orphaned reference. Earlier drafts scoped this work to SCANNER-CRYPTO-90-002/003; those task ids do not exist anywhere in the repo and have been removed as the authoritative tracking reference. The env-gated integration harness ops/crypto/run-rootpack-ru-tests.sh referenced below also does not exist (no ops/crypto/ directory). Sign-and-verify round-trips, oqs/liboqs-compatible interop verification, and SBOM/Policy attestation integration tests are not yet implemented and remain roadmap items.

Planned (Draft / roadmap, not yet implemented):

Rollout status

  1. Done — provider classes implemented under StellaOps.Cryptography.Plugin.PqSoft (BouncyCastle PQC, not oqs bindings).
  2. Done (partial) — provider is discovered via the plugin manifest (devops/etc/crypto-plugins-manifest.json, id pq.soft) and binds PqSoftProviderOptions. There is no Crypto:Providers appsettings registry.
  3. NOT IMPLEMENTED — DSSE signing-option plumbing in Scanner/Policy/Attestor hosts via a SigningProvider override (no such override keys exist).
  4. NOT IMPLEMENTED — env-gated tests in ops/crypto/run-rootpack-ru-tests.sh (script and directory absent).
  5. NOT IMPLEMENTED — operator guidance in docs/dev/crypto.md (file absent) and RootPack notes.

Risks / mitigations