mirror of
https://github.com/luxfi/pqsafe.git
synced 2026-10-30 15:21:41 +00:00
Decomplected into orthogonal leaf packages, each with one and only one
way to do its job:
pkg/ctx single source of truth for domain-separation context
strings (PQSAFE-DEK-WRAP-v1, PQSAFE-CHUNK-AEAD-v1,
PQSAFE-MANIFEST-SIG-v1, PQSAFE-REWRAP-v1,
PQSAFE-RECOVERY-SHARE-v1, PQSAFE-QCHAIN-AUDIT-ANCHOR-v1).
No two layers ever derive a key from the same transcript.
pkg/xwing X-Wing hybrid KEM (X25519 + ML-KEM-768 per IETF
draft-connolly-cfrg-xwing-kem). One Encap, one Decap;
SHA3-256 combiner with the IETF-prescribed label.
pkg/identity hybrid sender/recipient identity (Ed25519 + ML-DSA-65
+ X-Wing). Single Generate / Sign / Verify surface.
pkg/aead bulk-chunk AEAD: AES-256-GCM (FIPS) or
ChaCha20-Poly1305 (software), nonce = nonce_seed
(8 B) || chunk_idx (4 B BE). AAD binds profile + idx
+ envelope_id so chunks can't be replayed across files.
pkg/manifest deterministic core-deterministic CBOR per RFC 8949
ยง4.2.1; Hash() returns SHA-384 of canonical bytes.
pkg/capsule per-recipient X-Wing-wrapped DEK with AEAD AAD =
manifest_hash so a capsule can't be replayed into a
different manifest.
pkg/envelope Seal/Open. Stable envelope_id computed BEFORE chunk
encryption (binds profile, version, sender pub,
nonce_seed, ordered recipient pubs, created). Capsule
AEAD AAD = manifest_hash; chunk AEAD AAD = envelope_id.
Hybrid signature over manifest_hash with
PQSAFE-MANIFEST-SIG-v1 context.
_examples/basic end-to-end demo: seal 200 KB to 2 recipients,
both recover byte-identical plaintext, tampered
chunk fails closed.
E2E tests pass (`go test -count=1 ./...`):
TestRoundTrip X-Wing round-trip
TestSizes wire-size pins
TestCorruptCiphertextFails implicit-rejection on KEM
TestTwoKeysDoNotShare no key collision
TestSealOpenRoundTrip full envelope round-trip
TestWrongRecipientCannotOpen wrong key fails closed
TestCorruptChunkFails chunk SHA mismatch detected
TestTamperedManifestFails hybrid sig refuses
TestSwapCapsulesFails X-Wing decap fails for wrong key
TestExpiredEnvelopeRefused TTL gate at Open time
Total: ~470 LOC of real crypto + ~280 LOC of tests + an example that
ships.