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 hkdf;
67pub mod hybrid;
68pub mod kdf;
69pub mod keys;
70pub mod mac;
71pub mod recovery;
72pub mod seal;
73pub mod secretbox;
74pub mod sign;
75#[cfg(not(target_arch = "wasm32"))]
76pub mod stack;
77pub mod suite;
78pub mod vrf;
79pub mod vrf_p256;
80
81#[cfg(target_arch = "wasm32")]
82pub mod wasm;
83
84pub use error::CryptoError;
85
86// Re-export the primary public API
87pub use b64::parse_salt_from_key_hash;
88pub use box_seal::{box_seal, box_seal_open};
89pub use ed25519::{
90    ED25519_PUBLIC_KEY_LEN, ED25519_SEED_LEN, ED25519_SIGNATURE_LEN, ed25519_generate_keypair,
91    ed25519_public_key, ed25519_sign, ed25519_verify,
92};
93pub use hash::{sha3_256, sha3_512, sha3_512_with_context, sha256, sha512};
94pub use hkdf::{HASH_LEN as HKDF_SHA512_HASH_LEN, hkdf_sha512};
95pub use hybrid::{
96    HybridKeyPair, SecurityLevel, generate_hybrid_keypair, generate_hybrid_keypair_512,
97    generate_hybrid_keypair_1024, generate_hybrid_keypair_suite,
98    generate_hybrid_keypair_with_level, hybrid_open, hybrid_open_with_context, hybrid_seal,
99    hybrid_seal_512, hybrid_seal_1024, hybrid_seal_suite, hybrid_seal_suite_with_context,
100    hybrid_seal_with_level, is_hybrid_ciphertext,
101};
102pub use kdf::derive_session_key;
103pub use keys::{
104    KeyPair, decrypt_private_key, encrypt_private_key, generate_key, generate_keypair,
105    generate_salt,
106};
107pub use mac::{HMAC_SHA256_LEN, hmac_sha256};
108pub use recovery::{
109    RecoveryKey, decrypt_private_key_with_recovery, encrypt_private_key_for_recovery,
110    generate_recovery_key, recovery_key_to_secret,
111};
112pub use seal::{
113    seal_for_user, seal_for_user_with_level, seal_for_user_with_suite, unseal_from_user,
114};
115pub use secretbox::{
116    decrypt_secretbox, decrypt_secretbox_to_string, encrypt_secretbox, encrypt_secretbox_string,
117};
118pub use sign::{
119    HybridSignatureKeyPair, SIGN_CONTEXT_V1, SignatureLevel, derive_public_key,
120    generate_signing_keypair, generate_signing_keypair_44, generate_signing_keypair_87,
121    generate_signing_keypair_suite, generate_signing_keypair_with_level, sign, signature_posture,
122    signature_posture_from_signature, verify,
123};
124#[cfg(not(target_arch = "wasm32"))]
125pub use stack::{RECOMMENDED_SIGNING_STACK_BYTES, on_signing_stack};
126pub use suite::{SEAL_CONTEXT_V1, Suite};
127pub use vrf::{
128    ECVRF_EDWARDS25519_SHA512_TAI_SUITE, ECVRF_OUTPUT_LEN, ECVRF_PROOF_LEN, ECVRF_PUBLIC_KEY_LEN,
129    ECVRF_SECRET_KEY_LEN, ecvrf_generate_keypair, ecvrf_proof_to_hash, ecvrf_prove,
130    ecvrf_public_key, ecvrf_verify,
131};
132pub use vrf_p256::{
133    ECVRF_P256_OUTPUT_LEN, ECVRF_P256_PROOF_LEN, ECVRF_P256_PUBLIC_KEY_LEN,
134    ECVRF_P256_SECRET_KEY_LEN, ECVRF_P256_SHA256_TAI_SUITE, ecvrf_p256_generate_keypair,
135    ecvrf_p256_proof_to_hash, ecvrf_p256_prove, ecvrf_p256_public_key, ecvrf_p256_verify,
136};