Unified seal/unseal with automatic format detection.
This module provides the highest-level encryption API. It automatically selects the best available algorithm:
- If a post-quantum public key is provided, uses ML-KEM-768 + X25519 hybrid
- Otherwise, falls back to X25519 sealed box (NaCl-compatible)
On decryption, the format is auto-detected from the ciphertext header byte, so old (legacy) and new (PQ) ciphertexts can coexist seamlessly.
Usage
# Classical (X25519 only)
{pk, sk} = MetamorphicCrypto.Keys.generate_keypair()
{:ok, ct} = MetamorphicCrypto.Seal.seal_for_user("data", pk)
{:ok, "data"} = MetamorphicCrypto.Seal.unseal_from_user(ct, pk, sk)
# Post-quantum hybrid (automatic upgrade)
{pq_pk, pq_sk} = MetamorphicCrypto.Hybrid.generate_keypair()
{:ok, ct} = MetamorphicCrypto.Seal.seal_for_user("data", pk, pq_public_key: pq_pk)
{:ok, "data"} = MetamorphicCrypto.Seal.unseal_from_user(ct, pk, sk, pq_secret_key: pq_sk)
Summary
Functions
Seal plaintext (UTF-8 string) to a user's key(s).
Seal raw bytes (as base64) to a user's key(s).
Unseal ciphertext using the user's key(s). Auto-detects format.
Functions
@spec seal_for_user( plaintext :: String.t(), public_key_b64 :: String.t(), opts :: keyword() ) :: {:ok, String.t()} | {:error, String.t()}
Seal plaintext (UTF-8 string) to a user's key(s).
Options
:pq_public_key— if provided, uses hybrid ML-KEM-768 + X25519 encryption. Otherwise uses classical X25519 sealed box.
Examples
# Classical
{:ok, ct} = MetamorphicCrypto.Seal.seal_for_user("secret", public_key)
# Post-quantum
{:ok, ct} = MetamorphicCrypto.Seal.seal_for_user("secret", public_key, pq_public_key: pq_pk)
@spec seal_for_user_raw( plaintext_b64 :: String.t(), public_key_b64 :: String.t(), opts :: keyword() ) :: {:ok, String.t()} | {:error, String.t()}
Seal raw bytes (as base64) to a user's key(s).
Same as seal_for_user/3 but accepts pre-encoded base64 plaintext.
@spec unseal_from_user( ciphertext_b64 :: String.t(), public_key_b64 :: String.t(), private_key_b64 :: String.t(), opts :: keyword() ) :: {:ok, String.t()} | {:error, String.t()}
Unseal ciphertext using the user's key(s). Auto-detects format.
Options
:pq_secret_key— the hybrid ML-KEM secret key. Required for decrypting hybrid (v2) ciphertexts. Safe to always pass — legacy ciphertexts are detected and decrypted with the classical key regardless.
Examples
# Classical
{:ok, plaintext} = MetamorphicCrypto.Seal.unseal_from_user(ct, pk, sk)
# With PQ key available (auto-detects format)
{:ok, plaintext} = MetamorphicCrypto.Seal.unseal_from_user(ct, pk, sk, pq_secret_key: pq_sk)