Skip to content

feat: post-quantum dual-signature (Ed25519 + Dilithium3)#6

Closed
HaraldeRoessler wants to merge 1 commit into
MoltyCel:mainfrom
HaraldeRoessler:feat/pqc-dual-signature
Closed

feat: post-quantum dual-signature (Ed25519 + Dilithium3)#6
HaraldeRoessler wants to merge 1 commit into
MoltyCel:mainfrom
HaraldeRoessler:feat/pqc-dual-signature

Conversation

@HaraldeRoessler

Copy link
Copy Markdown
Contributor

Summary

Add quantum-safe signing to all Verifiable Credentials using ML-DSA-65 (Dilithium3) via liboqs (MIT licensed).

Every credential is now signed with both Ed25519 and Dilithium3. Old verifiers check Ed25519 and ignore Dilithium. New verifiers check both. This is Phase 1 of the PQC migration.

New files

File Purpose
app/crypto/dilithium.py Dilithium3 key management (KMS + env fallback), sign, verify
app/crypto/hybrid.py dual_sign() and verify_proof() for single or dual proofs
scripts/generate_dilithium_keys.py One-time keypair generation utility

Modified files

File Change
app/credentials.py issue_credential() uses dual_sign(), verify_credential() supports both formats
app/swarm/endorsement.py Endorsement VCs use dual_sign()
app/main.py DID document dynamically includes Dilithium key when configured

Graceful degradation

If DILITHIUM_PRIVATE_KEY_HEX (or KMS equivalent) is not set, the system issues Ed25519-only credentials exactly as before. No breaking change on deploy. Enable PQC by:

pip install liboqs-python
python scripts/generate_dilithium_keys.py
# Set the output as env vars
export DILITHIUM_PRIVATE_KEY_HEX=...
export DILITHIUM_PUBLIC_KEY_HEX=...

Credential format

Before (Ed25519 only):

{"proof": {"type": "Ed25519Signature2020", "proofValue": "64 bytes..."}}

After (dual-signature):

{"proof": [
  {"type": "Ed25519Signature2020", "verificationMethod": "...#key-ed25519", "proofValue": "64 bytes..."},
  {"type": "DilithiumSignature2026", "verificationMethod": "...#key-dilithium", "proofValue": "~2420 bytes..."}
]}

Migration path

  • Phase 1 (this PR): Dual-signature, Ed25519 + Dilithium
  • Phase 2 (future): Dilithium-first, Ed25519 deprecated
  • Phase 3 (future): Ed25519 sunset

Test plan

  • Deploy without Dilithium keys — verify Ed25519-only credentials still work
  • Generate Dilithium keypair and set env vars
  • Issue credential — verify proof is an array with both signatures
  • Verify dual-signed credential via /credentials/verify
  • Verify old Ed25519-only credential still passes verification
  • Check /.well-known/did.json includes Dilithium key when configured

Generated with Claude Code

Add quantum-safe signing to all Verifiable Credentials using ML-DSA-65
(Dilithium3) from liboqs (Open Quantum Safe, MIT licensed).

Architecture:
- app/crypto/dilithium.py: Dilithium3 key management, sign, verify
  with KMS-encrypted key support and plaintext fallback for dev
- app/crypto/hybrid.py: dual_sign() produces both Ed25519 and Dilithium
  proofs; verify_proof() validates single or dual proofs
- Graceful degradation: if Dilithium keys are not configured, falls
  back to Ed25519-only (no breaking change on deploy)

Changes:
- credentials.py: issue_credential() now uses dual_sign(), verify uses
  verify_proof() supporting legacy single-proof and new dual-proof
- endorsement.py: endorsement VCs use dual_sign()
- main.py: DID document dynamically includes Dilithium verification key
  when configured, with legacy key-1 alias for backward compatibility
- scripts/generate_dilithium_keys.py: utility to generate keypair

Migration path (from earlier discussion):
  Phase 1 (this PR): dual-signature, Ed25519 + Dilithium
  Phase 2 (future): Dilithium-first, Ed25519 deprecated
  Phase 3 (future): Ed25519 sunset

Dependency: liboqs-python (pip install liboqs-python)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@HaraldeRoessler

Copy link
Copy Markdown
Contributor Author

Superseded by #7 which combines JCS + PQC to avoid merge conflicts.

@HaraldeRoessler HaraldeRoessler deleted the feat/pqc-dual-signature branch May 12, 2026 00:08
HaraldeRoessler pushed a commit to HaraldeRoessler/moltrust-api that referenced this pull request Jul 3, 2026
…iew fixes

Erstes §12-Review (run 2026-05-28, label openclaw-plugin-v2.0.0-alpha.0)
fand 6 Blocker. Dieser PR adressiert 5 davon im Code + 1 als ADR-deferral.

Code-Fixes:
  - #1 Fail-Open Default → Neuer Config-Param `failOpen` (default false).
        before_tool_call + inbound_claim blocken jetzt bei API-Lookup-
        Fehlern, statt durchzulassen. Opt-in via failOpen=true.
  - #2 inbound_claim DENY-Ignorierung → Review-Befund war überwiegend
        Halluzination (Score-Check existierte schon), aber der Fail-Open-
        Pfad ist via #1 jetzt auch hier fail-closed.
  - MoltyCel#4 Cache TTL Default 300s → 10s (Zero-Trust Revocation-Latency).
  - MoltyCel#5 Vendored OpenClaw-Types ohne Versions-Anchor → Header-Kommentar
        in openclaw-types.ts pinnt jetzt explizit Range 0.9.x – 1.0.x
        + Anweisung „minor bump on upstream-breaking change". README
        zeigt Range in Architektur-Section.
  - MoltyCel#6 GDPR/Privacy → Neue README-Section „Privacy & Data Handling"
        listet explizit alle Endpoints, gesendete Datenfelder, Endpoint-
        URL, Retention-Pointer, Disable-Mechanismus.

ADR-Deferral:
  - MoltyCel#3 JWS Response-Signatur-Verifikation → ADR 0001 (docs/decisions/)
        erklärt warum v2.1 statt v2.0.0-alpha.1: braucht Bootstrap-/
        Rotations-/Failure-Mode-Design, eigener Sprint. Risiko-
        Mitigation in v2.0.0-alpha.1 durch #1 (kein Fall-Through bei
        API-unreachable). README-Section „Security Posture & Roadmap"
        kommuniziert v2.1-Plan + verbleibende MITM-Surface.

Publish-Prep (re-applied, since v2.0.0-alpha.0 origin/main state hat
diese noch nicht):
  - Paketname @moltrust/openclaw → @moltrust/openclaw-plugin
  - prepublishOnly, engines (node>=20), publishConfig.access: public
  - author, bugs, repository.url (Standardformat)
  - .gitignore + .npmignore

Tests: 27 → 31 (4 neue, fail-closed + opt-in-fail-open je hook).
py-equivalent: tsc + vitest grün, package size ~12 kB.

Re-§12-Review läuft nach Merge gegen das gleiche Briefing.
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.

1 participant