diff --git a/crypto/README.md b/crypto/README.md index 80e8f88..a3a6fee 100644 --- a/crypto/README.md +++ b/crypto/README.md @@ -4,11 +4,14 @@ Cryptographic primitives for the MTP protocol. Classical and post-quantum. ## Features -| Feature | Primitives | Status | -|---------|-----------|--------| -| `default` | XChaCha20-Poly1305, Ed25519, HKDF-SHA-256, SHA-256 | Classical | -| `full` | default + AES-256-GCM | Classical | -| `pqc` | ML-KEM-768+X25519 hybrid KEM, ML-DSA-65 | Post-quantum | +| Feature | Primitives | +|---------|-----------| +| `default` | XChaCha20-Poly1305, Ed25519, ML-DSA-65, HKDF-SHA-256, SHA-256 | +| `full` | default + AES-256-GCM | +| `pqc` | ML-KEM-768+X25519 hybrid KEM | + +ML-DSA-65 is enabled by default so dual-signature support is always available +without a separate PQC feature flag in protocol crates. ## AEAD @@ -71,21 +74,65 @@ let ss = HybridKem::decapsulate(&sk, &enc.ciphertext)?; assert_eq!(enc.shared_secret, ss); ``` +## Encrypted containers + +Self-describing encrypted blobs with algorithm selection via `EncryptionType`. +Each blob begins with a marking byte so recipients can decrypt without +out-of-band agreement. + +```rust +use mtp_crypto::{EncryptionType, Keyring, encrypt_for, decrypt_with}; + +let kr = Keyring::generate(); +let blob = encrypt_for(EncryptionType::MlKemChaCha20Poly1305, &kr.public_key_bundle(), b"data", b"aad")?; +let pt = decrypt_with(&blob, &kr, b"aad")?; +``` + +## Multi-recipient encryption + +Encrypt a payload for multiple recipients using a content-encryption key wrapped +per-recipient via Hybrid KEM. + +```rust +use mtp_crypto::{Keyring, encrypt_multi, decrypt_multi}; + +let alice = Keyring::generate(); +let bob = Keyring::generate(); +let msg = encrypt_multi(b"secret", b"aad", &[alice.public_key_bundle(), bob.public_key_bundle()])?; +let pt = decrypt_multi(&msg, b"aad", &alice)?; +``` + +## Authentication handshake + +Canonical domain-separated payloads for the challenge-response handshake. + +```rust +use mtp_crypto::auth::{challenge_payload, login_proof_payload, register_proof_payload, host_final_payload}; +``` + +Each payload type uses a distinct domain tag to prevent replay across protocol steps. + ## KDF ```rust -use mtp_crypto::{hkdf_expand, derive_encryption_key}; +use mtp_crypto::{hkdf_expand, hkdf_extract, derive_encryption_key}; let key = derive_encryption_key(b"ikm", b"salt", b"context")?; +let prk = hkdf_extract(b"ikm", b"salt"); ``` ## Hashing ```rust -use mtp_crypto::{sha256, sha256_double}; +use mtp_crypto::{sha256, sha256_double, Sha256Hasher}; let h = sha256(b"data"); let h2 = sha256_double(b"data"); + +let mut hasher = Sha256Hasher::new(); +hasher.update(b"da"); +hasher.update(b"ta"); +let h3 = hasher.finalize(); ``` ## Key types @@ -101,13 +148,17 @@ let h2 = sha256_double(b"data"); | `SignaturePqPrivateKey` | PQC signing key | Yes | | `SignaturePqPublicKey` | PQC verifying key | No | -`KeyGroup` holds classical keys; `Keyring` holds all six (hybrid KEM + PQ sig + classical sig). +`Keyring` holds all six keys (hybrid KEM + PQ sig + classical sig) plus +`generate()`, `to_bytes()`, and `from_bytes()` for serialization. +`PublicKeyBundle` holds the three public keys for distribution. ## Feature flags ```toml [dependencies] -mtp-crypto = { path = "../crypto" } # classical -mtp-crypto = { path = "../crypto", features = ["pqc"] } # post-quantum -mtp-crypto = { path = "../crypto", features = ["full", "pqc"] } # all +mtp-crypto = { path = "../crypto" } # classical + ML-DSA +mtp-crypto = { path = "../crypto", features = ["pqc"] } # adds hybrid KEM +mtp-crypto = { path = "../crypto", features = ["full", "pqc"] } # adds AES-256-GCM + hybrid KEM +mtp-crypto = { path = "../crypto", features = ["serde"] } # serde support +mtp-crypto = { path = "../crypto", features = ["wasm"] } # WASM compat ```