Axiom flagship (3) — real hybrid Ed448+Dilithium5 certificate signing (G01) - #48
Merged
Merged
Conversation
…uth layer) Adds the authenticating-signature half of G01: an opt-in, real cryptographic signing path for certificates using only vetted primitives. The default digest-only path is byte-for-byte unchanged (still authenticated=false). - crypto/: new axiom_crypto Rust cdylib. Ed448 via OpenSSL libcrypto; Dilithium5 (ML-DSA-87 / FIPS 204) via pqcrypto-dilithium (the family opsm ships). Clean C ABI (caller-allocates + returned length), minimal unsafe each with // SAFETY, 7 Rust round-trip / tamper / wrong-key tests. - src/verification/signing.jl: Libdl loader + generate_hybrid_keypair / hybrid_sign / hybrid_verify (requires BOTH Ed448 AND Dilithium5) + a runtime ABI self-check (which caught a real Dilithium5 signature-length mismatch during development). - certificates.jl: opt-in sign_certificate_hybrid / verify_certificate_hybrid / save_certificate_hybrid; signs the SHA3-512 digest of the canonical content (estate hashing standard); canonical content includes the properties list so a property cannot be added/removed without invalidating the signature. Default path untouched. - test/verification/hybrid_signing_tests.jl: real round-trip + THE KEY ASSERTION -- a forger who recomputes the exact SHA3-512 digest but lacks the private keys CANNOT produce a signature that verifies against the victim public keys. - Justfile build-crypto/test-crypto; ROADMAP private-key custody story (HSM/offline; public-keys-only-in-certs; rotation/revocation flagged). NO private keys in-repo. Verified: crypto cargo test 7/7; full Julia suite 697/697 with the hybrid path executing; forged certificate rejected; no key material committed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UPFC9YQ7g9gc3VnRox42Q1
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
Closes the authenticating‑signature half of G01 — the certificate can now carry a real cryptographic signature, not just a forgeable content digest. This is opt‑in: the default
generate_certificate/save_certificatepath is byte‑for‑byte unchanged (authenticated=false, SHA‑256 content digest), so nothing downstream breaks.Uses only vetted primitives (no hand‑rolled crypto), matching the estate Trustfile scheme and the
pqcryptofamilyopsmalready ships.What's added
crypto/— newaxiom_cryptoRust cdylib. Ed448 via OpenSSL libcrypto; Dilithium5 (ML‑DSA‑87 / FIPS 204) viapqcrypto-dilithium. Clean C ABI (caller‑allocates + returned length), minimalunsafeeach with a// SAFETY:comment, 7 Rust round‑trip/tamper/wrong‑key tests.src/verification/signing.jl—Libdlloader +generate_hybrid_keypair/hybrid_sign/hybrid_verify. Verification is AND — both Ed448 and Dilithium5 must verify (an attacker must break both to forge). Includes a runtime ABI self‑check that caught a real Dilithium5 signature‑length mismatch (4627, not the 4595 first assumed) during development.certificates.jl— opt‑insign_certificate_hybrid/verify_certificate_hybrid/save_certificate_hybrid. Signs the SHA3‑512 digest (estate hashing standard) of the canonical content, which includes the properties list so a claimed property can't be added/removed without invalidating the signature.test/verification/hybrid_signing_tests.jl— real round‑trip + THE KEY ASSERTION: a forger who knows the exact content and recomputes the SHA3‑512 digest but lacks the private keys cannot produce a signature that verifies against the victim's public keys (plus a self‑verify sanity check proving it's authentication, not a crypto malfunction).Justfilebuild-crypto/test-crypto;ROADMAP.adocdocuments the shipped capability and the private‑key custody story (HSM/offline signer; public keys only in certificates; rotation/revocation explicitly flagged as not‑yet‑implemented).Key‑management stance
No private key material is committed anywhere (verified). Certificates embed only public keys; signing keys are generated out‑of‑band.
Verification (independent re‑run; crypto reviewed by hand)
cd crypto && cargo test --release→ 7/7 pass.Pkg.test()→ 697 / 697 pass (670 + 27 new), hybrid path actually executing (not skipped)._hybrid_verify_digest— confirmed AND semantics and realccallinto the cdylib (no mock).Tracked follow‑ups
SPHINCS+ fallback tier; key rotation/revocation; the estate‑wide Ed448‑vs‑Ed25519 reconciliation (
opsmcurrently uses Ed25519 — flagged for owner); wiringbuild-cryptointo CI as part of the tier‑2 tooling wave.🤖 Generated with Claude Code
https://claude.ai/code/session_01UPFC9YQ7g9gc3VnRox42Q1
Generated by Claude Code