f0rest8
Hey all — I open-sourced an Elixir library that a few people in my previous threads might find useful.
metamorphic_crypto is a NaCl-compatible encryption library for Elixir with post-quantum support, powered by a Rust NIF core with precompiled binaries. It provides:
- Symmetric encryption — XSalsa20-Poly1305 (NaCl secretbox)
- Public-key encryption — X25519 sealed boxes
- Hybrid post-quantum encryption — ML-KEM-768 + X25519 (NIST FIPS 203)
- Key derivation — Argon2id (libsodium-compatible parameters)
- Recovery keys — human-readable backup codes (like Signal/Matrix)
- Auto-detecting ciphertext — seals with PQ when available, falls back to classical, detects format on decrypt
The Rust core is #![forbid(unsafe_code)], built entirely on audited RustCrypto primitives, and ships via rustler_precompiled — so it’s just mix deps.get for end users. No Rust toolchain, no C compiler, no system packages.
Why I built this: If you’ve ever tried to get enacl compiling on a fresh machine or in CI, you know the pain — libsodium headers, C toolchain, breakage on OTP upgrades. This library produces identical NaCl ciphertext but ships as precompiled binaries. It also adds ML-KEM-768 post-quantum encryption that nothing else on Hex offers.
What it’s for:
- Swap-in for some
enaclfunctions — same wire format, no data migration, no libsodium dependency - Server-side NaCl-compatible crypto in Phoenix apps
- Post-quantum encryption (ML-KEM-768 + X25519, first on Hex)
- Wire compatibility with browser WASM clients (same Rust core compiles to both NIF and WASM)
What it’s NOT: This library runs server-side. It doesn’t give you client-side zero-knowledge encryption by itself. For full ZK where the server never sees plaintext, you need client-side crypto in the browser (we use WASM). But if your server needs NaCl crypto — key generation, sealing to recipients, test fixtures, or a migration path toward ZK — this is the tool.
If you’re using enacl today, the secretbox and sealed box operations are wire-compatible. You can swap those calls with no data migration.
What’s next: I’m transitioning Mosslet (currently using enacl) to this library as a first step — it’s a straightforward swap that gives us precompiled binaries and PQ-readiness before we add the client-side WASM layer.
Zero-Knowledge: This repo also seemed a fitting place to include a Zero-Knowledge Phoenix Guide that walks through implementing full client-side encryption in LiveView — the architecture behind Metamorphic. The guide covers the WASM client setup, key hierarchy, LiveView hooks, and where the server-side library fits in (spoiler: for a full ZK app, the server mostly just stores opaque blobs).
elixir
# mix.exs
{:metamorphic_crypto, "~> 0.1”}
elixir
key = MetamorphicCrypto.generate_key()
{:ok, ct} = MetamorphicCrypto.encrypt("hello", key)
{:ok, "hello"} = MetamorphicCrypto.decrypt(ct, key)
# Post-quantum hybrid
{pk, sk} = MetamorphicCrypto.Hybrid.generate_keypair()
{:ok, sealed} = MetamorphicCrypto.Hybrid.seal("quantum-safe", pk)
{:ok, "quantum-safe"} = MetamorphicCrypto.Hybrid.open(sealed, sk)
Hex: hex.pm/packages/metamorphic_crypto
github.com/moss-piglet/metamorphic_crypto
Happy to answer questions or hear feedback.
For context on the architecture behind this, I wrote about the zero-knowledge LiveView encryption approach and the Mosslet project in earlier posts.
Trending in Announcing
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixir-ls
- #ai
- #elixirconf-us
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 2- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
f0rest8
Update: v0.1.2 released
Okay, I updated Mosslet to fully replace
:enaclin production. In doing so, I discovered a few fixes we needed to make to themetamorphic_cryptolibrary, but the crypto itself worked as hoped.metamorphic_crypto v0.1.2 (library fixes):
Mosslet (production swap):
enaclentirely — no more C compiler, libsodium system dependency, or CI patchesmetamorphic_cryptov0.1.2 — precompiled Rust NIFs, same NaCl wire formatdecrypt_string(UTF-8 text) first, falls back to rawdecryptfor binary data like images. The library provides both APIs by design; Mosslet’s wrapperhandles the routing.Performance: Noticeably faster — the Rust NIFs outperform enacl’s C NIFs, and on a timeline page that decrypts dozens of posts (usernames, bodies, avatar key unsealing), the gains compound.
What’s next — Mosslet’s path to zero-knowledge:
Phase 2: Post-quantum hybrid key wrapping (server-side NIFs)
pq_public_key/encrypted_pq_private_keycolumns to usersMetamorphicCrypto.HybridMetamorphicCrypto.Seal.seal_for_user/3withpq_public_key:optionunseal_from_user/4auto-detects legacy vs hybrid format — old data keeps workingPhase 3: Full ZK with WASM (like Metamorphic)
metamorphic-cryptoWASM build toassets/vendor/I’m hopeful because the
metamorphic_cryptolibrary is so far working as expected. Since the NIF and WASM are compiled from the same Rust crate, data sealed by the server (Phase 2) can be unsealed by the browser (Phase 3) and vice versa. I can move features to client-side ZK one at a time without breaking anything.https://github.com/moss-piglet/metamorphic_crypto
f0rest8
Updated: Changelog for v0.2.0 (2026-05-13)
metamorphic-cryptoRust source tometamorphic-cryptov0.2.0 on crates.io (no user-facing changes — the public Elixir API is backwards compatible)MetamorphicCrypto.Hybrid.generate_keypair_1024/0— generate Cat-5 keypairMetamorphicCrypto.Hybrid.seal_1024/2— encrypt with Cat-5MetamorphicCrypto.Hybrid.seal_raw_1024/2— encrypt raw bytes with Cat-5MetamorphicCrypto.Hybrid.open/2now auto-detects Cat-3 (v2) and Cat-5 (v3) ciphertextMetamorphicCrypto.Hybrid.hybrid_ciphertext?/1now detects both v2 and v3 formatsIf you’re using
:metamorphic_cryptoin your Phoenix app, update yourmix.exsto{:metamorphic_crypto, "~> 0.2"}and runmix deps.getormix deps.update metamorphic_cryptoif you’re lock version is earlier. No code changes needed — the API is backwards compatible.Also updated our zk phoenix guide to reflect the improved flow using the rust crate.