Zero-knowledge end-to-end encryption for Elixir.
MetamorphicCrypto provides NaCl-compatible cryptographic primitives powered
by Rust NIFs with precompiled binaries — no Rust toolchain required.
Quick Start
# Generate keys
key = MetamorphicCrypto.generate_key()
{public_key, private_key} = MetamorphicCrypto.generate_keypair()
# Symmetric encryption (XSalsa20-Poly1305)
{:ok, ciphertext} = MetamorphicCrypto.encrypt("hello", key)
{:ok, "hello"} = MetamorphicCrypto.decrypt(ciphertext, key)
# Public-key encryption (X25519 sealed box)
{:ok, sealed} = MetamorphicCrypto.seal("secret", public_key)
{:ok, "secret"} = MetamorphicCrypto.unseal(sealed, public_key, private_key)Modules
For full control, use the specialized modules directly:
MetamorphicCrypto.SecretBox— symmetric encryptionMetamorphicCrypto.BoxSeal— public-key encryptionMetamorphicCrypto.Hybrid— ML-KEM-768 + X25519 post-quantumMetamorphicCrypto.Seal— unified seal/unseal (auto-detects format)MetamorphicCrypto.KDF— Argon2id key derivationMetamorphicCrypto.Keys— key generation and managementMetamorphicCrypto.Recovery— human-readable recovery keys
Wire Format
All functions accept and return base64-encoded strings. Ciphertext produced
by this library is byte-compatible with libsodium/NaCl and the
metamorphic-crypto WASM module used in browser clients.
Summary
Functions
Decrypt a ciphertext back to a UTF-8 string.
Encrypt a UTF-8 string with a symmetric key.
Generate a random 32-byte symmetric key (base64-encoded).
Generate an X25519 keypair.
Encrypt a UTF-8 string to a recipient's public key (anonymous sealed box).
Decrypt a sealed box using the recipient's keypair.
Functions
@spec decrypt(ciphertext :: String.t(), key :: String.t()) :: {:ok, String.t()} | {:error, String.t()}
Decrypt a ciphertext back to a UTF-8 string.
Example
{:ok, "hello, world!"} = MetamorphicCrypto.decrypt(ciphertext, key)
@spec encrypt(plaintext :: String.t(), key :: String.t()) :: {:ok, String.t()} | {:error, String.t()}
Encrypt a UTF-8 string with a symmetric key.
Uses XSalsa20-Poly1305 (NaCl secretbox). Returns base64-encoded ciphertext.
Example
key = MetamorphicCrypto.generate_key()
{:ok, ciphertext} = MetamorphicCrypto.encrypt("hello, world!", key)
@spec generate_key() :: String.t()
Generate a random 32-byte symmetric key (base64-encoded).
Example
key = MetamorphicCrypto.generate_key()
Generate an X25519 keypair.
Returns {public_key, private_key} as base64-encoded strings.
Example
{public_key, private_key} = MetamorphicCrypto.generate_keypair()
@spec seal(plaintext :: String.t(), public_key :: String.t()) :: {:ok, String.t()} | {:error, String.t()}
Encrypt a UTF-8 string to a recipient's public key (anonymous sealed box).
The sender remains anonymous — only the recipient can decrypt.
Example
{public_key, _private_key} = MetamorphicCrypto.generate_keypair()
{:ok, sealed} = MetamorphicCrypto.seal("secret message", public_key)
@spec unseal( ciphertext :: String.t(), public_key :: String.t(), private_key :: String.t() ) :: {:ok, String.t()} | {:error, String.t()}
Decrypt a sealed box using the recipient's keypair.
Example
{public_key, private_key} = MetamorphicCrypto.generate_keypair()
{:ok, sealed} = MetamorphicCrypto.seal("secret", public_key)
{:ok, "secret"} = MetamorphicCrypto.unseal(sealed, public_key, private_key)