Stage375 extends Stage374 by adding real ML-DSA-65 signing and verification for the same Stage373 attestation blob already signed and verified through Sigstore, Cosign, GitHub Actions OIDC, and Rekor.
Stage374 established:
- GitHub Actions OIDC identity
- Cosign signing
- Sigstore bundle verification
- Rekor inclusion verification
- concrete Rekor log position
external_transparency_bound: true
Stage375 adds:
- a real ML-DSA-65 key pair
- ML-DSA-65 signing
- ML-DSA-65 signature verification
- public-key fingerprint verification
- exact target binding with the Stage374 Sigstore signature
- logical attestation hash consistency
- fail-closed PQC downgrade prevention
The same Stage373 file is signed through two independent signature rails:
- Stage374 Sigstore / Cosign / Rekor
- Stage375 ML-DSA-65
Both signatures must target:
docs/final-acceptance-attestation/stage373_final_acceptance_attestation.json
Expected blob SHA256:
6ecf58d0070d8db920744b7d32331e01e8e1aef2eded02dde428b80def79d5e6
Expected logical attestation SHA256:
d54b7524ced420f664da9d370985585d649ce80584b64bdf87342f89dbfde89f
Before the GitHub Actions ML-DSA workflow runs:
decision: mldsa_execution_pendingmldsa_signature_verified: falsedual_signature_target_matches: falsepqc_downgrade_prevented: false
After complete ML-DSA signing and verification:
decision: quantum_safe_dual_signature_verifiedsigstore_signature_verified: truerekor_inclusion_verified: truemldsa_signature_verified: truedual_signature_target_matches: truepqc_downgrade_prevented: true
Stage375 uses:
pqc_required: truedowngrade_policy: fail_closed
After ML-DSA execution begins, a missing, invalid, removed, or mismatched ML-DSA signature causes block.
A valid Sigstore signature alone is not sufficient when the PQC policy is active.
The ML-DSA private key:
- is created locally
- remains under
private/stage375-mldsa/ - is excluded by
.gitignore - is excluded from Git and may remain in the local private directory; the production workflow receives a copy through an encrypted GitHub Actions secret
- is reconstructed temporarily inside the GitHub Actions runner
- has its temporary runner copy deleted before artifact upload
- is never published in GitHub Pages or the repository
The public key and ML-DSA signature may be public.
Stage375 uses OpenSSL 3.5.7 LTS in GitHub Actions.
OpenSSL 3.5 introduced native ML-DSA-44, ML-DSA-65, and ML-DSA-87 support.
This stage claims use of the FIPS 204 ML-DSA algorithm.
It does not claim that the custom-built OpenSSL binary is a FIPS 140 validated cryptographic module.
docs/mldsa-production/stage375_mldsa65_input.jsondocs/mldsa-production/stage375_mldsa65_public_key.pemdocs/mldsa-production/stage375_mldsa65_signature.bindocs/mldsa-production/stage375_mldsa65_execution_receipt.jsondocs/mldsa-production/stage375_dual_signature_verification_result.jsondocs/mldsa-production/stage375_dual_signature_verification_summary.txt
Stage375 does not publish:
- ML-DSA private keys
- ML-DSA seeds
- OIDC tokens
- GitHub tokens
- raw QKD key material
- raw timestamp binaries
- free-form shell commands
MIT License.
Stage375 completed real ML-DSA-65 signing and verification.
Current result:
decision: quantum_safe_dual_signature_verifiedsigstore_signature_verified: truerekor_inclusion_verified: truemldsa_signature_verified: truedual_signature_target_matches: truepqc_downgrade_prevented: true- GitHub Actions run:
29327350883 - OpenSSL version:
3.5.7 - ML-DSA signature size:
3309 bytes
The Stage374 Sigstore/Rekor signature and the Stage375 ML-DSA-65 signature target the same Stage373 attestation blob.
The ML-DSA private key was not published. A local development copy may remain under the Git-ignored private/stage375-mldsa/ directory, while the production workflow uses an encrypted GitHub Actions secret.