Elixir bindings to Matrix's Olm and Megolm cryptographic primitives, built on top of Element's vodozemac (Rust) via Rustler.
This library wraps the protocol primitives only — talking to a homeserver, persisting serialized session state, and routing decrypted events are caller concerns.
Surface
- Account — long-term Curve25519 + Ed25519 identity for a
device. Generates one-time keys and is the input to outbound
Olm sessions. (
account_*functions.) - Olm session — pairwise channel between two devices, used
to share Megolm room keys. (
olm_*functions.) - Megolm group session — symmetric ratchet for one sender
fanning out to many receivers. (
*_group_sessionfunctions.) - Cross-signing — raw Ed25519/Curve25519 helpers used by Matrix's cross-signing identities.
- SAS — short-authentication-string verification primitives.
Persistence
All session state serializes to an opaque pickle binary. The
pickle is currently wrapped with vodozemac's default zero-key
(no confidentiality at rest); callers must apply their own
encryption layer until a pickle_key parameter lands in a later
release.
Stability
Pre-1.0. Function signatures may move before the API freezes; see
CHANGELOG.md and the README's stability table.
Summary
Functions
Create a fresh Olm account; returns its libolm-compatible pickle.
Generate up to count new one-time keys. Returns the updated
account pickle and a list of {key_id_b64, public_key_b64} tuples.
Return the device's identity keys as {curve25519_b64, ed25519_b64}.
Mark all unpublished one-time keys as published after /keys/upload.
Maximum number of one-time keys the account holds (vodozemac uses 50).
Sign message with the account's Ed25519 key.
Perform an X25519 Diffie-Hellman between our base64-encoded secret key and a peer's base64-encoded public key. Returns the 32-byte shared secret (raw bytes), ready to feed into HKDF.
Generate a fresh Curve25519 keypair. Returns {secret_b64, public_b64}.
Used by the Megolm key backup (phase 5c) where the public key
encrypts every stored session under an ephemeral-static ECDH wrap.
Generate a fresh Ed25519 keypair. Returns
{secret_b64, public_b64} — base64 strings ready to embed in
Matrix cross-signing payloads. The caller is responsible for
persisting (and ideally encrypting) the secret.
Recover the base64 public key from a base64 Ed25519 secret key.
Sign message with the given base64 Ed25519 secret key.
Build an InboundGroupSession from the base64 session_key field
of an m.room_key to-device event. Returns the session id (which
matches the timeline event's session_id) and the pickle to
persist.
Decrypt a Megolm timeline ciphertext. Returns plaintext, the message index for replay defence, and the updated pickle (the session ratchets internal state on decrypt).
Return the session id of an inbound Megolm group session. Same id
that the original sender embeds in m.room.encrypted events; use
it to look up the correct inbound session per incoming event.
Decrypt an inbound pre-key (type 0) Olm message, establishing the inbound session in the process. Returns plaintext, the session id, the session pickle to persist, and the updated account pickle.
Establish an outbound Olm session against a peer device. Returns the session id, the session pickle, and a new account pickle (the account's internal state advances).
Decrypt with an existing Olm session.
Encrypt with an existing Olm session. Returns {type, ciphertext, new_pickle}.
Return the session id of an Olm pairwise session. Both ends of a successfully-established session derive the same id, so callers can use it as a dedupe key when multiple pre-key messages race.
Create a fresh outbound group session. Returns the session id, the
base64 session_key (to be wrapped in m.room_key events and
shared with peers), and the pickle.
Encrypt plaintext with the outbound group session.
Return the session id of an outbound Megolm group session. This is
the value to publish in the session_id field of every
m.room.encrypted event you send under this session so that
recipients can match it to the corresponding inbound session.
Extract the current Megolm session key from an outbound session
pickle. Use the result as the session_key field of an
m.room_key to-device payload.
Index of the next message the outbound session would encrypt (i.e. how many ratchet steps have been taken). Used to record the starting index when uploading a session to server-side key backup; receivers can only decrypt messages at or after the index they were keyed at.
Derive the SAS bytes for the given info string. Returns the seven emoji indices (0–63 each) and a 3-tuple of decimals to show alongside.
Compute a base64 MAC over input with the given info string.
Perform ECDH with the peer's curve25519 public key. Consumes the
pre-DH handle (any subsequent use returns :sas_consumed) and
produces an established_sas handle.
Create a fresh SAS instance with an ephemeral curve25519 keypair.
Returns {handle, public_key_b64} — the handle is an opaque
Rust-side reference; persist nothing about it, just thread it
through subsequent SAS calls in the same BEAM process.
Verify a peer-computed MAC. Returns :ok or {:error, :bad_message}.
Verify an Ed25519 signature.
Functions
@spec account_create() :: binary()
Create a fresh Olm account; returns its libolm-compatible pickle.
@spec account_generate_one_time_keys(binary(), non_neg_integer()) :: {binary(), [{binary(), binary()}]}
Generate up to count new one-time keys. Returns the updated
account pickle and a list of {key_id_b64, public_key_b64} tuples.
Return the device's identity keys as {curve25519_b64, ed25519_b64}.
Mark all unpublished one-time keys as published after /keys/upload.
@spec account_max_one_time_keys(binary()) :: non_neg_integer()
Maximum number of one-time keys the account holds (vodozemac uses 50).
Sign message with the account's Ed25519 key.
Perform an X25519 Diffie-Hellman between our base64-encoded secret key and a peer's base64-encoded public key. Returns the 32-byte shared secret (raw bytes), ready to feed into HKDF.
Generate a fresh Curve25519 keypair. Returns {secret_b64, public_b64}.
Used by the Megolm key backup (phase 5c) where the public key
encrypts every stored session under an ephemeral-static ECDH wrap.
Generate a fresh Ed25519 keypair. Returns
{secret_b64, public_b64} — base64 strings ready to embed in
Matrix cross-signing payloads. The caller is responsible for
persisting (and ideally encrypting) the secret.
Recover the base64 public key from a base64 Ed25519 secret key.
Sign message with the given base64 Ed25519 secret key.
Build an InboundGroupSession from the base64 session_key field
of an m.room_key to-device event. Returns the session id (which
matches the timeline event's session_id) and the pickle to
persist.
@spec inbound_group_session_decrypt(binary(), binary()) :: {plaintext :: binary(), message_index :: non_neg_integer(), new_pickle :: binary()}
Decrypt a Megolm timeline ciphertext. Returns plaintext, the message index for replay defence, and the updated pickle (the session ratchets internal state on decrypt).
Return the session id of an inbound Megolm group session. Same id
that the original sender embeds in m.room.encrypted events; use
it to look up the correct inbound session per incoming event.
@spec olm_session_create_inbound(binary(), binary(), binary()) :: {plaintext :: binary(), session_id :: binary(), session_pickle :: binary(), new_account_pickle :: binary()}
Decrypt an inbound pre-key (type 0) Olm message, establishing the inbound session in the process. Returns plaintext, the session id, the session pickle to persist, and the updated account pickle.
@spec olm_session_create_outbound(binary(), binary(), binary()) :: {session_id :: binary(), session_pickle :: binary(), new_account_pickle :: binary()}
Establish an outbound Olm session against a peer device. Returns the session id, the session pickle, and a new account pickle (the account's internal state advances).
@spec olm_session_decrypt(binary(), 0 | 1, binary()) :: {plaintext :: binary(), new_pickle :: binary()}
Decrypt with an existing Olm session.
@spec olm_session_encrypt(binary(), iodata()) :: {message_type :: 0 | 1, ciphertext_b64 :: binary(), new_pickle :: binary()}
Encrypt with an existing Olm session. Returns {type, ciphertext, new_pickle}.
Return the session id of an Olm pairwise session. Both ends of a successfully-established session derive the same id, so callers can use it as a dedupe key when multiple pre-key messages race.
@spec outbound_group_session_create() :: {session_id :: binary(), session_key :: binary(), pickle :: binary()}
Create a fresh outbound group session. Returns the session id, the
base64 session_key (to be wrapped in m.room_key events and
shared with peers), and the pickle.
@spec outbound_group_session_encrypt(binary(), iodata()) :: {ciphertext_b64 :: binary(), new_pickle :: binary()}
Encrypt plaintext with the outbound group session.
Return the session id of an outbound Megolm group session. This is
the value to publish in the session_id field of every
m.room.encrypted event you send under this session so that
recipients can match it to the corresponding inbound session.
Extract the current Megolm session key from an outbound session
pickle. Use the result as the session_key field of an
m.room_key to-device payload.
@spec outbound_group_session_message_index(binary()) :: non_neg_integer()
Index of the next message the outbound session would encrypt (i.e. how many ratchet steps have been taken). Used to record the starting index when uploading a session to server-side key backup; receivers can only decrypt messages at or after the index they were keyed at.
@spec sas_bytes(reference(), binary()) :: {[non_neg_integer()], {non_neg_integer(), non_neg_integer(), non_neg_integer()}}
Derive the SAS bytes for the given info string. Returns the seven emoji indices (0–63 each) and a 3-tuple of decimals to show alongside.
Compute a base64 MAC over input with the given info string.
Perform ECDH with the peer's curve25519 public key. Consumes the
pre-DH handle (any subsequent use returns :sas_consumed) and
produces an established_sas handle.
Create a fresh SAS instance with an ephemeral curve25519 keypair.
Returns {handle, public_key_b64} — the handle is an opaque
Rust-side reference; persist nothing about it, just thread it
through subsequent SAS calls in the same BEAM process.
Verify a peer-computed MAC. Returns :ok or {:error, :bad_message}.
Verify an Ed25519 signature.