Skip to main content

metamorphic_crypto/
lib.rs

1//! # metamorphic-crypto
2//!
3//! Zero-knowledge end-to-end encryption core for the Metamorphic platform.
4//!
5//! This library implements the cryptographic operations required by all Metamorphic
6//! clients (web/WASM, iOS/UniFFI, Android/UniFFI). It produces byte-compatible
7//! ciphertext with the existing JavaScript implementation so that data encrypted
8//! by one client can be decrypted by any other.
9//!
10//! ## Security guarantees
11//!
12//! - All secret key material is [`Zeroize`]-on-drop
13//! - No `unsafe` code
14//! - Constant-time comparisons via the underlying RustCrypto crates
15//! - Randomness sourced directly from the OS CSPRNG ([`getrandom`])
16//!
17//! ## Ciphertext formats
18//!
19//! The legacy `Suite::Hybrid` (default) formats are byte-for-byte unchanged. The
20//! opt-in CNSA 2.0 suites use an AES-256-GCM envelope keyed by
21//! `HKDF-SHA512(info = suite_tag || context_label)` (see [`suite`]); the
22//! `nonce (12B) || ct || gcm_tag (16B)` portion is the AEAD output.
23//!
24//! | Format | Layout |
25//! |--------|--------|
26//! | Secretbox | `nonce (24B) \|\| ciphertext (len + 16B MAC)` |
27//! | box_seal | `ephemeral_pk (32B) \|\| box ciphertext` |
28//! | Hybrid v1 (Cat-1) | `0x01 \|\| ML-KEM-512 ct (768B) \|\| X25519 eph pk (32B) \|\| nonce (24B) \|\| secretbox ct` |
29//! | Hybrid v2 (Cat-3) | `0x02 \|\| ML-KEM-768 ct (1088B) \|\| X25519 eph pk (32B) \|\| nonce (24B) \|\| secretbox ct` |
30//! | Hybrid v3 (Cat-5) | `0x03 \|\| ML-KEM-1024 ct (1568B) \|\| X25519 eph pk (32B) \|\| nonce (24B) \|\| secretbox ct` |
31//! | PureCnsa2 (Cat-5) | `0x10 \|\| ML-KEM-1024 ct (1568B) \|\| nonce (12B) \|\| ct \|\| gcm_tag (16B)` |
32//! | HybridMatched (Cat-3) | `0x13 \|\| ML-KEM-768 ct (1088B) \|\| X448 eph pk (56B) \|\| nonce (12B) \|\| ct \|\| gcm_tag (16B)` |
33//! | HybridMatched (Cat-5) | `0x14 \|\| ML-KEM-1024 ct (1568B) \|\| P-521 eph pk (133B) \|\| nonce (12B) \|\| ct \|\| gcm_tag (16B)` |
34//!
35//! ## Signature formats
36//!
37//! The default `Suite::Hybrid` is a composite ML-DSA + Ed25519 signature with
38//! strict-AND verification. The opt-in CNSA 2.0 suites place the fixed-size
39//! classical component first (so the variable ML-DSA tail needs no length
40//! prefix) and reuse the same I2OSP domain-separation framing. `PureCnsa2` has
41//! no classical component. All are strict-AND verified.
42//!
43//! | Suite (level) | signature | public_key | secret_key |
44//! |---------------|-----------|------------|------------|
45//! | Hybrid (Cat-2/3/5) | `tag \|\| ed25519_sig (64B) \|\| ml_dsa_sig` | `tag \|\| ed25519_pk (32B) \|\| ml_dsa_pk` | `tag \|\| ed25519_seed (32B) \|\| ml_dsa_seed (32B)` |
46//! | HybridMatched (Cat-3) | `0x13 \|\| ed448_sig (114B) \|\| ml_dsa65_sig` | `0x13 \|\| ed448_pk (57B) \|\| ml_dsa65_pk` | `0x13 \|\| ed448_seed (57B) \|\| ml_dsa_seed (32B)` |
47//! | HybridMatched (Cat-5) | `0x14 \|\| ecdsa_p521_sig (132B) \|\| ml_dsa87_sig` | `0x14 \|\| p521_pk (133B) \|\| ml_dsa87_pk` | `0x14 \|\| p521_seed (66B) \|\| ml_dsa_seed (32B)` |
48//! | PureCnsa2 (Cat-5) | `0x10 \|\| ml_dsa87_sig` | `0x10 \|\| ml_dsa87_pk` | `0x10 \|\| ml_dsa_seed (32B)` |
49//!
50//! Separately, the [`ed25519`] module exposes **bare RFC 8032 Ed25519**
51//! (sign/verify, no framing, no PQ component). It exists *only* for byte-level
52//! interoperability with the deployed C2SP transparency-log witness ecosystem
53//! (Go `sumdb/note`, sigsum, transparency-dev, Tessera), which co-signs
54//! checkpoints with raw Ed25519. It is **not** a general-purpose signing API —
55//! use the hybrid PQ [`sign`] for Metamorphic authenticity.
56
57#![forbid(unsafe_code)]
58#![deny(missing_docs)]
59
60pub mod b64;
61pub mod box_seal;
62mod ecc;
63pub mod ed25519;
64pub mod error;
65pub mod hash;
66pub mod hybrid;
67pub mod kdf;
68pub mod keys;
69pub mod mac;
70pub mod recovery;
71pub mod seal;
72pub mod secretbox;
73pub mod sign;
74pub mod suite;
75pub mod vrf;
76pub mod vrf_p256;
77
78#[cfg(target_arch = "wasm32")]
79pub mod wasm;
80
81pub use error::CryptoError;
82
83// Re-export the primary public API
84pub use b64::parse_salt_from_key_hash;
85pub use box_seal::{box_seal, box_seal_open};
86pub use ed25519::{
87    ED25519_PUBLIC_KEY_LEN, ED25519_SEED_LEN, ED25519_SIGNATURE_LEN, ed25519_generate_keypair,
88    ed25519_public_key, ed25519_sign, ed25519_verify,
89};
90pub use hash::{sha3_256, sha3_512, sha3_512_with_context, sha256, sha512};
91pub use hybrid::{
92    HybridKeyPair, SecurityLevel, generate_hybrid_keypair, generate_hybrid_keypair_512,
93    generate_hybrid_keypair_1024, generate_hybrid_keypair_suite,
94    generate_hybrid_keypair_with_level, hybrid_open, hybrid_open_with_context, hybrid_seal,
95    hybrid_seal_512, hybrid_seal_1024, hybrid_seal_suite, hybrid_seal_suite_with_context,
96    hybrid_seal_with_level, is_hybrid_ciphertext,
97};
98pub use kdf::derive_session_key;
99pub use keys::{
100    KeyPair, decrypt_private_key, encrypt_private_key, generate_key, generate_keypair,
101    generate_salt,
102};
103pub use mac::{HMAC_SHA256_LEN, hmac_sha256};
104pub use recovery::{
105    RecoveryKey, decrypt_private_key_with_recovery, encrypt_private_key_for_recovery,
106    generate_recovery_key, recovery_key_to_secret,
107};
108pub use seal::{
109    seal_for_user, seal_for_user_with_level, seal_for_user_with_suite, unseal_from_user,
110};
111pub use secretbox::{
112    decrypt_secretbox, decrypt_secretbox_to_string, encrypt_secretbox, encrypt_secretbox_string,
113};
114pub use sign::{
115    HybridSignatureKeyPair, SIGN_CONTEXT_V1, SignatureLevel, derive_public_key,
116    generate_signing_keypair, generate_signing_keypair_44, generate_signing_keypair_87,
117    generate_signing_keypair_suite, generate_signing_keypair_with_level, sign, signature_posture,
118    signature_posture_from_signature, verify,
119};
120pub use suite::{SEAL_CONTEXT_V1, Suite};
121pub use vrf::{
122    ECVRF_EDWARDS25519_SHA512_TAI_SUITE, ECVRF_OUTPUT_LEN, ECVRF_PROOF_LEN, ECVRF_PUBLIC_KEY_LEN,
123    ECVRF_SECRET_KEY_LEN, ecvrf_generate_keypair, ecvrf_proof_to_hash, ecvrf_prove,
124    ecvrf_public_key, ecvrf_verify,
125};
126pub use vrf_p256::{
127    ECVRF_P256_OUTPUT_LEN, ECVRF_P256_PROOF_LEN, ECVRF_P256_PUBLIC_KEY_LEN,
128    ECVRF_P256_SECRET_KEY_LEN, ECVRF_P256_SHA256_TAI_SUITE, ecvrf_p256_generate_keypair,
129    ecvrf_p256_proof_to_hash, ecvrf_p256_prove, ecvrf_p256_public_key, ecvrf_p256_verify,
130};