The Marmot Protocol is an open specification for encrypted group messaging built on Nostr and the MLS cryptographic protocol. At its March 10, 2026 snapshot, the design is documented across six Marmot Implementation Proposals, MIP-00 through MIP-05. Four are mandatory for any compatible implementation, and two are optional extensions. Together they describe how a group of people can exchange encrypted messages over a decentralized relay network while spreading trust across relays, storage servers and a notification server.
The privacy protection has a definite shape. Encryption covers message content and group state, and a fresh signing key for each event hides which member published it. Other facts stay observable. Every group message carries a public routing identifier, and relays, storage hosts and network observers can see IP addresses, timing and event sizes. A user who knows where that boundary sits can judge Marmot accurately. Below, each spec is described by what it protects and what it leaves exposed.
MIP-00: Your invitation card#
Every messaging system begins with identity. MIP-00 builds Marmot identity on your Nostr keypair, the same identity you use across Nostr clients. It links that keypair to a separate MLS signing key that authenticates your messages inside encrypted groups. The separation is deliberate. Losing control of a group signing key is a different event from losing control of your Nostr key.
To be reachable for invitations, you publish a KeyPackage event (kind 443) to Nostr relays. A KeyPackage is public by design. It advertises your supported cryptographic capabilities, your credential and an init_key, which is an HPKE public key. Someone who wants to add you uses that public key to encrypt the group secrets inside a Welcome message, described under MIP-02. The KeyPackage works like a business card left at a front desk: anyone can read it, and it tells people how to reach you. The analogy stops at the card's contents. Those contents are public keys and capability data, and the invitation itself arrives later, in the Welcome.
The private half of the init_key stays on your device, and that private key decrypts the Welcome's group secrets. MIP-00 gives it a lifecycle. The general rule says the private init_key SHOULD be securely deleted after you join a group through a Welcome. The deletion-timing rules are stricter. For a single-use KeyPackage, the client MUST delete the private init_key immediately after successfully processing the Welcome, which the MLS library normally handles. For a last-resort KeyPackage, the client MUST retain the private key as long as that KeyPackage remains published or may be needed to decrypt Welcomes. It MUST delete the key once the KeyPackage is rotated and the old one is unpublished. Secure deletion means zeroizing the key in memory and removing it from persistent storage. Backups either leave the key out or are updated to drop it.
Deletion protects past invitations against later device compromise. Suppose an attacker records Welcome messages from relays and later seizes your device. By then the private init_key is gone, so the recorded Welcomes stay sealed. The public KeyPackages were readable all along and contain only public material.
MIP-00 also handles races. Several Welcomes can arrive for one KeyPackage in the window between discovery and delivery. Implementations SHOULD either track pending invitations and delay deletion briefly, or accept that later Welcomes for a consumed KeyPackage fail and the inviter retries with a different KeyPackage. The last-resort KeyPackage covers that window, and rotation limits how long its private key has to live. Members also refresh their key material over time through self-update Commits, covered under MIP-02 and MIP-03.
MIP-01: Building the room#
With identities in place, MIP-01 defines how groups are built. Each MLS group has a random 32-byte group ID that is private and permanent and is never published to relays in any form. A second identifier, the nostr_group_id, lives in the Marmot Group Data Extension. It is a separate 32-byte random value that MAY change over time through group proposals. It appears in the h tag of every group message. Relays and anyone reading relay traffic can see the nostr_group_id and use it to collect events from one conversation. The private MLS group ID stays inside the group, and the public nostr_group_id is the handle outsiders can observe.
Before creating a group, a client checks the intended members' published KeyPackages for compatible cryptographic parameters, so that every invitee's client can decrypt the group. The creator then sets up the initial MLS state, including the ratchet tree that manages keys as members join and leave.
The Marmot Group Data Extension carries Nostr-specific metadata inside the authenticated MLS group state. That metadata includes a version field (currently 2), the nostr_group_id, the group name and description, admin public keys, relay URLs, and the seeds and nonce for the encrypted group image. Any member can propose a change to these fields, and only an admin can commit one: before processing any Commit that modifies this extension, clients MUST verify that the committer is listed in admin_pubkeys. Self-update Commits leave the extension untouched and need no admin authorization. A relay operator who wanted to rename a group or insert an admin key would need a valid Commit from a listed admin, and members reject anything else.
Group avatars are encrypted with ChaCha20-Poly1305. The key is derived through HKDF from the image_key seed and the nonce is a random 12-byte image_nonce. The encrypted blob goes to a Blossom server. Upload authentication uses a Nostr keypair derived from image_upload_key, a seed that is cryptographically independent of image_key, so the upload credential and the encryption key stay isolated. When an admin replaces the image, members who saw the earlier extension state can derive the old upload keypair and ask for the old blob to be deleted.
MIP-02: Getting through the door#
MIP-02 defines Welcome Events (kind 444). A Welcome gives a new member the group secrets, the current member state, the ratchet tree and the active extensions, including the MIP-01 metadata.
Welcomes travel inside NIP-59 gift wrapping. A random one-time key signs the outer gift wrap, which hides the original sender from relays. The outer event also carries the recipient's p tag so relays can route it, which means a relay sees who the Welcome is addressed to. Inside, the rumor is unsigned. A leaked rumor lacks a portable Nostr signature, so relays and clients reject it and outsiders have nothing to authenticate it against. NIP-59 calls this a measure of deniability. Anyone holding leaked bytes can still read the content and repeat it as an unverifiable claim.
MIP-02 is strict about ordering. The admin adding a member MUST wait for relays to confirm the Commit before sending the Welcome, and the rule covers every addition after the group is first created. A Welcome contains group state at a specific epoch. If it reaches the new member before the Commit reaches existing members, the group forks into two states whose messages each side fails to decrypt. A central server would enforce ordering for everyone, but Nostr relays can deliver events out of order, so MIP-02 gives the waiting duty to the admin.
After joining, the new member's LeafNode holds key material from the KeyPackage used to add them. MLS keeps that leaf's encryption key separate from the init_key: RFC 9420 requires the two values to differ. The private init_key decrypts the Welcome, and MIP-00's deletion rules protect a captured Welcome by destroying that key. Later group secrets are encrypted through the ratchet tree to the leaf key. MIP-02's dated rationale blurs this split, saying that until the member updates their LeafNode, a compromise of the init_key private material could allow decryption of group secrets. Under RFC 9420, the exposure a self-update repairs belongs to the leaf key. Its public half sat in the published KeyPackage. Its private half was created along with that KeyPackage, which can happen well before the join. If that private key leaks, group secrets keep being encrypted to a compromised key until the member replaces it.
A self-update closes that window. It replaces the leaf with fresh key material that was never published and advances the epoch, so later group secrets go to a key the attacker lacks, provided the attacker no longer has access to the device. It leaves the init_key alone, and a Welcome captured earlier depends on MIP-00 deletion for its protection. MIP-02 recommends processing outstanding Commits first, then self-updating as soon as possible, ideally before sending application messages. It requires the self-update within 24 hours of joining, even if catch-up is partial because relays are unavailable. A client that is still catching up SHOULD keep trying and hold back application messages until it confirms it is on the current epoch.
MIP-03: Talking and governing#
MIP-03 defines Group Events (kind 445). These carry control messages for managing the group and application messages for conversation.
Each Group Event's content is a serialized MLSMessage encrypted with ChaCha20-Poly1305, under a key derived from the current epoch's MLS exporter secret. Within an epoch that key stays fixed, so nonce uniqueness is the sole protection against keystream reuse. MIP-03 requires a fresh 12-byte nonce from a secure random generator for every event. If the client detects a duplicate outbound nonce, it MUST NOT send the event and SHOULD self-update to rotate the key. If the generator fails, encryption MUST abort. Falling back to a deterministic or low-entropy nonce is forbidden.
Each Group Event is signed by an ephemeral Nostr keypair that MUST differ for every event. Relay observers see a fresh pubkey on every message, which stops them from linking messages to a sender through signing keys. The h tag carries the nostr_group_id for routing and filtering, so relays and observers can tell which messages belong to the same group and when that group is active. Network observation adds more. A relay sees the connecting IP address and the timing of each publish and fetch. It also sees ciphertext sizes. Clients that want to blunt those signals need network-layer protections beyond the scope of MIP-03.
Governance runs through proposals and Commits. Any member can propose adding or removing someone or changing settings. Admins listed in admin_pubkeys can commit any proposal. Any member, admin or otherwise, MAY create a self-update Commit, whose sole proposal is an Update for the committer's own LeafNode. Clients check both rules and reject invalid Commits. Because of this, every member can keep their own forward secrecy and post-compromise security current on their own authority.
When competing Commits arrive for one epoch, clients MUST apply exactly one. The Commit with the earliest created_at wins, with ties going to the lexicographically smallest event id. Clients discard the rest. Clients that see the same Commits converge on the same state. Clients SHOULD also keep earlier group states for a while so they can recover from forks.
Inside the encryption, application messages use standard Nostr event formats such as kind 9 for chat and kind 7 for reactions. Inner events carry the sender's real Nostr pubkey, and clients MUST verify that the MLS sender matches it. Inner events MUST stay unsigned and must leave out h tags and other group identifiers. A leaked inner event therefore lacks a signature relays would accept and carries no explicit group identifier, though whatever its content says remains readable to anyone holding it.
MIP-04: Sharing files privately#
MIP-04 is optional and covers media such as images, video, audio and documents. A client encrypts the file, uploads the encrypted blob to content-addressed storage such as Blossom, and shares the decryption metadata through the group's encrypted channel in an imeta tag.
The current version is mip04-v2. It uses ChaCha20-Poly1305 with keys derived from the MLS exporter secret and random nonces stored in the imeta tag, and every new imeta tag MUST include v mip04-v2. Version 1 derived nonces deterministically through HKDF. Encrypting the same file content twice with the same filename therefore produced identical nonces, a nonce-reuse risk the spec itself calls a vulnerability. Version 1 is deprecated and MUST NOT be used for new media. The migration section says clients MUST reject mip04-v1 tags and SHOULD show warnings, and legacy v1 media may no longer decrypt. Every version puts a scheme label into key derivation and AAD, which keeps versions cryptographically separate.
The spec describes the privacy properties of this design in strong terms. Storage addresses are hashes of encrypted content and the MLS group is the decryption boundary. Historical media also stays closed to new members. Encryption hides file contents. Each address is the SHA-256 digest of the ciphertext, and if ChaCha20-Poly1305 and the key derivation behave as assumed, random nonces and epoch-derived keys make that ciphertext look unrelated to the plaintext, so a storage server that hashes a known file gets a value that matches no stored blob. The spec's phrase "no correlation" holds for that link between files and addresses and needs a limit beyond it. A storage server still sees who uploads and fetches each blob, from which IP addresses, at what times and at what sizes, and those access patterns can link blobs to each other and to users.
Version 2 supports single-blob objects, with each file encrypted and stored as one atomic unit. Chunked encryption, streaming decryption, multi-part uploads with per-chunk keys, and cross-group deduplication are explicitly out of scope. Size and timeout limits are left to libraries and applications.
MIP-05: Notifications without surveillance#
Push notifications are a common place for encrypted messengers to leak metadata. A message can be well encrypted while the push that wakes the phone passes through Apple's APNs or Google's FCM. Those services see that a device received a notification from an app at a given time. MIP-05, the second optional spec, works within that exposure for clients that use these platform services. It aims to reduce what the notification server and group members learn, while APNs and FCM still observe deliveries.
Your client builds a 220-byte padded payload holding a platform byte, the token length, the device token and random padding. It encrypts that payload to the notification server's hardcoded public key. The scheme uses a fresh ephemeral secp256k1 keypair with ECDH plus HKDF, then ChaCha20-Poly1305 with a random 12-byte nonce. Every encrypted token comes to 280 bytes. That total combines a 32-byte ephemeral pubkey and a 12-byte nonce with 236 bytes of ciphertext including the tag.
The server decrypts each token and reads the platform and the device token in plaintext. Encrypting the same token for two groups produces different ciphertexts, so group members and relay observers see unlinkable blobs. After decryption, the server sees the same device token both times and can match it across groups and over time. MIP-05 says probabilistic encryption prevents the server from correlating a user's presence across groups. That mechanism backs the claim for ciphertexts. It falls short for the decrypted token, which the server has to read to deliver the push.
Padding every token to 280 bytes stops group members from guessing whether someone uses iOS or Android from token size. The server learns the platform when it decrypts, because the platform byte sits inside the payload.
To trigger notifications, a sender collects encrypted tokens from active leaves, adds decoys, shuffles everything, and sends the bundle as an unsigned kind 446 rumor. The seal is signed with the same ephemeral key as the rumor, and the outer gift wrap uses a separate ephemeral key. Decoys are real encrypted tokens. About half the time the sender includes their own token. The sender also adds tokens from their other Marmot groups, at 10 to 20 percent of the real count with a minimum of three decoys in total. Decoy recipients get a silent wake, check relays and go back to sleep. Padding events toward a minimum of about ten tokens and randomizing created_at timestamps add more cover. Because kind 446 events use ephemeral pubkeys, rate limiting falls to relay-level mechanisms.
Decoys add statistical noise and make group size and bundle membership harder to infer. The server still sees which decrypted tokens arrive together, and watching repeated bundles over time can separate tokens that consistently appear together from random decoys. The spec also notes a leak when members use different notification servers. The bundles then reveal which servers they use and therefore which clients.
Tokens are shared inside the encrypted MLS channel as kinds 447, 448 and 449, carried as application messages in kind 445 events. A joining member shares their encrypted token and asks for the others' tokens. Members reply with their lists. Clients drop tokens from leaves that have left the tree.
MIP-05 requires iOS clients to use APNs tokens and forbids sending iOS notifications through FCM as a proxy. The spec's reasoning is that if FCM handled both platforms, Google could match users across iOS and Android and across groups. That rule limits what Google sees. Apple still sees iOS deliveries, and Google still sees Android deliveries.
What this means for users#
Marmot needs no phone number or email address, and your identity is your Nostr keypair. Each infrastructure operator learns a limited set of facts. Relay operators see ciphertext, ephemeral pubkeys for each event, the public nostr_group_id in each h tag, recipient p tags on gift-wrapped Welcomes, and the IP addresses, timing and sizes of traffic. From that they can learn when a group is active and roughly how much it sends. They can also learn which network addresses take part, unless clients hide that at the network layer. Storage servers hold encrypted blobs and see upload and access metadata. The notification server reads device tokens and platforms, and APNs and FCM see deliveries. Group content stays sealed to outsiders. The fact that a group exists, and the pattern of its activity, is partly visible to anyone placed to watch routing and traffic. Users facing a capable network observer need protection at the network layer, which Marmot leaves to the transport.
At this snapshot Marmot was experimental. The README from that date says the specification was under active development and could change in breaking ways. It also says the protocol had not yet undergone formal security auditing and that reference implementations were functional but may contain bugs. It names MDK as the Rust reference implementation and marmot-ts as a TypeScript implementation described as being at an early stage, and it lists White Noise as a project building a messenger on MDK. MLS is standardized by the IETF as RFC 9420. That standard covers MLS itself. Whether the complete Marmot construction is sound, including its Nostr transport, gift wrapping, exporter-derived encryption and notification design, is a separate question that formal auditing had yet to answer by that date. Readers who want group messaging with privacy built in at the protocol layer can read the six specs with these limits in mind and try the software as experimental.


Comments0
No comments yet. Start the conversation.