Cryptographic Primitives
DraftSingle source of truth for primitives; other docs link here, never restate. Constants: capsule-core/src/crypto/primitives.rs.
Primitives Inventory
Section titled “Primitives Inventory”| Primitive | Choice | Used for |
|---|---|---|
| Cryptographic hash | SHA-256 | Content addressing, integrity |
| Key derivation | HKDF-SHA512 | Per-file, per-blob, per-album keys |
| Password-based KDF | Argon2id, device-tier parameters | Escrow and backup unwrap |
| Bulk AEAD | AES-256-GCM (+ STREAM) | Asset and metadata ciphertext |
| MLS control AEAD | ChaCha20-Poly1305 | MLS’s own messages |
| Signature scheme | Hybrid Ed25519 + ML-DSA-65 | Identity, device, manifest, write tier |
| KEM | X-Wing (X25519 + ML-KEM-768) | MLS HPKE |
| MLS ciphersuite | MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 (0x004D) | Group key management |
| Randomness | OS CSPRNG (getrandom) | All keys, salts, nonces |
| Transport | TLS 1.3, hybrid X25519+ML-KEM | Client–server, server–server |
Versioning Identifiers
Section titled “Versioning Identifiers”Mismatches fail closed:
| Identifier | Type | Owner | Carried in |
|---|---|---|---|
crypto_suite_id | u16 | this doc | every AssetManifest, metadata blob, backup MANIFEST.cbor |
protocol_version | YYYY-MM-DD | Versioning | every AssetManifest, every request (negotiation), the album’s MLS pin |
sidecar_schema | u16 | Metadata | CBOR sidecar field 0 |
crypto_suite_id = 0x0001is exactly the inventory above. Retiring a primitive adds a new suite id; it never edits the existing row. Old suite ids stay verifiable and decryptable forever.- Suite ids are a Capsule namespace, unrelated to MLS ciphersuite codepoints.
- Manifest signatures cover
crypto_suite_idandprotocol_version, so a downgrade cannot be produced silently.
Per-Primitive Choices
Section titled “Per-Primitive Choices”Cryptographic Hash
Section titled “Cryptographic Hash”SHA-256 everywhere; the content-address hash is the value the signed manifest commits to and upload verifies.
Key Derivation
Section titled “Key Derivation”HKDF-SHA512 (wider hash keeps ~256-bit margin under Grover). Every derivation MUST use a versioned info string and a scope-unique salt.
Password-based KDF
Section titled “Password-based KDF”Argon2id, 32-byte random salt, recovery/bootstrap only. Cost is chosen by device tier at wrap time (DeviceTier::params), stored in-band, and honoured at unwrap on any device.
Bulk AEAD
Section titled “Bulk AEAD”AES-256-GCM (hardware-accelerated on every target). Nonce misuse is closed structurally: a fresh per-encryption file key for STREAM, a fresh CSPRNG nonce per metadata blob (Re-keying on Rewrite).
MLS Control AEAD
Section titled “MLS Control AEAD”Fixed by the MLS ciphersuite; MLS messages only, never user data.
Signature Scheme
Section titled “Signature Scheme”| Signature | Scheme |
|---|---|
| Long-lived identity/evidence: user IK, device keys, manifests, write-tier keys, custody receipts and storage attestations | Hybrid Ed25519 + ML-DSA-65; both halves MUST verify |
| Short-lived operational: server–server federation, federation capabilities, access-token JWTs | Ed25519 only |
| MLS LeafNode | Ed25519 (ciphersuite-pinned); the ML-DSA half lives at the identity layer (MLS) |
The boundary is signature lifetime, not signer: a server-signed custody receipt is long-lived evidence, so it is hybrid.
Defined by the MLS ciphersuite.
MLS Ciphersuite
Section titled “MLS Ciphersuite”0x004D, the X-Wing suite from draft-mahy-mls-xwing that OpenMLS ships via libcrux — not draft-ietf-mls-pq-ciphersuites. Its SHA-256 is MLS-internal and independent of the content-address hash. Rationale and migration posture: MLS.
Randomness
Section titled “Randomness”OS CSPRNG only; never a self-seeded PRNG or hand-rolled nonce.
Validation
Section titled “Validation”- Known-answer vectors (RFC, RustCrypto, OpenMLS) for every primitive.
- Suite-id round-trip: persisted
crypto_suite_iddispatches to exactly its row. - Downgrade rejection: a manifest whose declared suite differs from its signed envelope is rejected.