Plenum

A Privacy-First Multisig Wallet
(That Normal People Can Actually Use)

Working draft · June 2026 · PlenumWallet.com

Abstract

Plenum is a multisig wallet for Monero, built around one goal: make privacy multisig usable by normal people, not just by experts. The technology exists. Monero has had multisig for years, yet almost nobody uses it, because setup means trading rounds of cryptographic blobs by hand, getting everyone online at once, and never making a mistake. Backing it up properly is just as hostile to normal users, since the recovery material is not a simple seed phrase. These are walls only experts get over. Plenum removes them: usable multisig out of the box, automated coordination, and backups that survive a lost device, while keeping the on-chain activity and the coordination metadata hidden.

Contents

1. Motivation

Monero has had m-of-n multisig for years, but almost nobody uses it. The problem is not the cryptography, it is usability: setup means several manual rounds of swapping key-exchange blobs, everyone online at the same time, long hex copied without error, and one mistake forces a restart. So the feature sits unused while the need (shared treasuries, group custody, escrow) goes unmet.

On transparent chains, mainstream wallets turned shared custody into a click-through commodity, but everything they do is public on-chain forever. That leaves a gap nobody fills: multisig that is both usable and private. Plenum fills it, with the usability of those wallets and the privacy of Monero.

2. Core Features

The mainstream multisig wallets serve the transparent smart-contract world. Plenum is the counterpart for Monero: multisig and shared custody that are ready to use, without every step being visible on-chain or in cleartext.

  1. Usable m-of-n Monero multisig. Shared custody out of the box, without the user wiring up the crypto layer. Monero first because it is the largest privacy market, and threshold signing for it is now practical (4.2).
  2. Automated setup ceremony. A two-round FROST distributed key generation runs automatically, coordinated by a one-time master (a bootstrap role only, no lasting privilege; the group is leaderless afterward) instead of hand-swapping message blobs.
  3. Privacy by default. Both the on-chain activity and the coordination metadata stay hidden, unlike the transparent-chain incumbents where every transaction, signer, and threshold is public on-chain.
  4. Anonymity-network transport. All messaging is encrypted with MLS (Messaging Layer Security, RFC 9420: the IETF standard for end-to-end encrypted group messaging, with forward secrecy, authenticated membership, and a transport-agnostic design), delivered over SimpleX SMP queues as a store-and-forward bus (4.4) and reached over Tor or Nym, the member's own choice, with no plain-clearnet path. The queue servers are storage, not identity.
  5. Group channel. Each multisig gets one MLS group serving three roles: social chat, coordination and spend approval, and distributed backup with store-and-forward for offline members.
  6. Redundant encrypted backup. One encrypted blob, replicated to three destinations: locally, off-site on S3-compatible stores (ciphertext-only), and with the other group members. Only the user's own seed opens it.
  7. Self-service recovery. If a device is lost, the user restores the wallet from any surviving copy of the backup using their own seed. The seed derives the key the backup is encrypted under; the member's per-group identity, like the FROST share, is generated at setup and rides inside the blob, so restoring any surviving copy reconstitutes everything without other members having to participate.
  8. Fully open source, end to end. No proprietary components; a self-custody privacy wallet must be auditable. The building blocks are already free and open (an MLS implementation, Tor/Nym, monero-serai and the FROST threshold-signing libraries). Plenum is licensed GPL-3.0, which also satisfies the copyleft of the linked Nym code.
  9. Optional auditable mode. A group can decide, unanimously (n-of-n), to take on a persistent public identity under a chosen alias, and then sign statements and prove its reserves m-of-n (8). It is off by default and uses a separate identity key, so going public never exposes the spend key, the rendezvous, or members' network identities.

3. System overview

Plenum's architecture rests on one construct, the group channel, and one membership rule. This section defines both; the later sections build on them.

3.1 The group channel

Every multisig group gets its own group channel. From the user's point of view it is always "the group has a chat." Technically it is one MLS group running over the anonymity-network transport.

The channel serves three roles at once:

  1. Social space. By default a chat room where the members can simply talk. Not only machine coordination, but a real group chat for the people behind the wallet. This lowers the barrier and keeps the group active, which also makes it a more robust backup network.

  2. Coordination. Wallets and users exchange setup rounds, signature collection, spend proposals, and notifications ("your signature is needed"). The interactive multisig setup messages and the approval of each spend flow through here, in the same place as the chat.

  3. Distributed backup and offline store. Each member stores its encrypted backup blob with the other members over the same channel, and holds the others' blobs in return. The blobs are ciphertext to everyone but their owner, so this is redundant storage, not shared access: a fellow member can hand your backup back to you but cannot open it. If a member is offline, the others hold the data destined for it (store and forward) where it makes sense, and on reconnect it receives the queued messages and updates. Nobody has to be online at the same time.

3.2 Access control

For a Monero multisig the membership rule is simple: membership equals "you are one of the n signers." A static list that changes only when the multisig is set up again. The MLS group mirrors the signers exactly: the signer set and the channel membership are one and the same.

When the signer set changes (a member leaves or is replaced), Plenum forms a brand-new group with new keys (6.1), so the former member shares nothing with it; there is no in-group remove. Within a live group, members ratchet forward with periodic MLS Update commits, which gives forward secrecy without any membership change: a key compromised at one moment does not expose past or future epochs.

4. Transport and privacy

Everything the group sends is an MLS-encrypted payload, delivered over SimpleX SMP queues used as a store-and-forward bus (4.4), so no member has to host a reachable service: each client only connects out to SMP servers. Each client reaches those servers over an anonymity network, Tor or Nym, that hides its IP; there is no plain-clearnet path. This section covers that anonymity choice, the cryptography under it, the queue substrate, and how members find one another.

4.1 Transport and messaging

Plenum has a single class of transport: an MLS-encrypted payload delivered over SimpleX SMP queues (4.4) and reached over an anonymity network. There is no public cleartext path and no broadcast. Everything (setup, coordination, spend approval, backups) is end-to-end encrypted by MLS, a server sees only opaque ciphertext landing in a short-lived, epoch-rotated queue with no stable identifier, and the anonymity layer (Tor or Nym, 4.3) hides each member's IP.

MLS is transport-agnostic, so the same encrypted group runs over either network. See 4.3 for what Tor and Nym each protect and where each one's protection ends.

4.2 Cryptographic building blocks

For the wallet itself, Plenum uses FROST (the IETF threshold-Schnorr scheme) applied to Monero's CLSAG, via a maintained implementation such as modular-frost, with monero-serai for building and signing the transactions. FROST gives true m-of-n threshold signing in which every signer holds a single secret share and the distributed key generation is a fixed two-round exchange, avoiding the combinatorial key blow-up and the N-M+1 round count of Monero's native multisig. Maturity here splits by path, which matters because this is money-moving code. The CLSAG path is the reviewed one: the Monero transaction library was audited in 2025, and the threshold-CLSAG scheme has a published formalization and security proof. The path Plenum actually targets, the post-FCMP++ FROST-GSP threshold signing (status note below), is designed but not yet audited: its proving-circuit audits have not started and it is not production-ready. Either way the usable libraries are pre-1.0 git revisions rather than released crates, so the signing core stays behind a swap boundary, the audited CLSAG path is the documented interim and fallback rather than a claim that the targeted code is reviewed, and an independent review of Plenum's own integration is required before it holds funds. On status: the setup, coordination, channel, and backup layers are buildable today, while the transaction-signing core is targeted at the FCMP++/CARROT fork, the path that removes ring selection, so spending arrives with that fork rather than on day one. On the interim CLSAG path the deterministic build also leaves a reproducible-ring pattern that can mark a transaction as a coordinated multisig (not its amount or recipient), which the FCMP++ target eliminates along with ring selection itself.

Why a plain MLS library rather than an MLS-over-chat SDK. Existing MLS messengers bundle the protocol with a transport binding. Such an SDK wraps the same OpenMLS core, then adds stable-pubkey identities, key-package discovery by pubkey, and persistently addressed events. That binding is exactly the metadata pattern Plenum avoids: a persistent pubkey links every action to one long-lived identity, and the setup rounds form a recognizable fingerprint. Plenum's delivery (4.4) does the opposite, addressing only epoch-rotated queues that no server can link across epochs, and it keeps the network choice open (Tor or Nym, 4.3). So Plenum reuses the MLS engine (OpenMLS) directly and supplies its own identity, delivery, and transport layers, rather than inheriting a chat SDK's network coupling. Reusing such an SDK would mean adopting the very identity and delivery model the design rejects.

4.3 Anonymity network: Tor or Nym

The connection to the SMP servers must be anonymized; otherwise a server would see each member's IP. Every member reaches the servers over one of two networks, an individual choice, with no plain-clearnet option:

Timing defence on both tiers. The synchronized signing rounds are the real timing risk, so both tiers randomize the timing of those rounds (jitter) and pad them with cover traffic. That blurs the burst-and-round pattern against a nosy server, a single network observer, or a chain-timing correlator, which is the realistic adversary. What jitter and cover cannot do is build a cross-user anonymity set: only Nym's mixing defeats a global passive adversary watching both ends at once. Jitter is not mixing.

The network choice is per member, but timing privacy is a group property: because a spend is a synchronized event, the weakest network choice in the group bounds the timing privacy of the shared spend, not just that one member's own flow. A group with a high protection requirement can therefore require Nym for every member as a group-level policy. The client always routes over one of the two and offers no cleartext path; concrete library and wiring details are in Appendix B.

4.4 Delivery substrate: SimpleX SMP queues

Delivery runs over SimpleX SMP queues used as a store-and-forward bus. SMP gives exactly the primitive Plenum needs: unidirectional message queues with no global account or identifier, where the server holds a message until the recipient pulls it and deletes it after acknowledgement. That delivers reliably to offline members, the case a pure flood-and-pull substrate handles worst, while keeping the server blind to who is talking to whom. The practical posture is unchanged: no member has to host a reachable service, every client only connects out to SMP servers, and self-hosting an SMP server is trivial on low-power Linux for a group that wants its own.

SMP queues are addressed (a recipient pulls its own queue), which is the deliberate trade against the old flood model: Plenum buys reliable store-and-forward and pays with an address the server can see. Four properties keep that address from becoming a stable identifier or a group fingerprint:

What it does not buy: it does not remove the need for the anonymity layer. The server still sees the connecting IP; only Tor or Nym hides that (4.3). The SMP layer protects the application layer (no global identity, rotating addresses, padded frames), not the network layer.

The anonymity-network choice stays per member here too: a server only ever sees an inbound connection, so the IP it sees is whatever network the connecting member used, and each member's Tor-or-Nym choice (4.3) protects that member's own connection. The servers never receive a cleartext connection.

The trade-off of leaning on SMP servers is a dependency on server liveness, rate limits, and censorship. All are mitigated by spreading queues across several servers and rotating off any that misbehave; a group may also self-host. Against the old flood bus the gain is reliable delivery to offline members; the cost is a per-epoch queue address visible to one server, bounded by rotation, spreading, and per-circuit isolation so that nothing stable or group-wide is exposed.

4.5 Identity, addressing, and rendezvous

Identity. A member's identity is a long-term MLS credential keypair generated freshly for each group, not derived from the user's seed, so a member carries a different, unlinkable identity in every group they join: nothing on the wire or in the credential ties their presence in one group to another. Like the FROST share, this keypair is produced at setup and is not regenerable from the seed; it lives inside the encrypted backup blob (6.1) and is recovered by restoring a surviving copy. The hash of its public key is the member_id used throughout that group, and it maps to the member's Monero signer position established during setup (5.1). Within a group the same key authenticates the member across setup, coordination, and backup; there is no account, no external directory, and no identity shared between groups.

Addressing. Members never dial one another by any standing address. Each member's inbound queue address (4.4) is derived from the shared MLS epoch secret and rotates every epoch, so the whole group recomputes the current set of queues from common state rather than storing it: each member polls its own queue and pushes to the others'. There is no address book and no per-member transport address that outlives an epoch.

Forward-secret operational queues. Everyday coordination runs on per-member queues whose addresses derive from the group's current MLS epoch secret, which ratchets on every commit, so a secret captured later cannot reconstruct past queue addresses and an observer cannot retroactively locate the group's historical traffic:

queue_addr(member, epoch) = KDF(mls_exporter_secret(epoch), member_id, time_epoch)

Every member derives the same set of queue addresses from the shared epoch state and resumes pushing and pulling there; they rotate with both the MLS epoch and the time epoch. For the harder case where every member was offline long enough to fall out of MLS-epoch sync, a separate recovery queue is the backstop, its address built so that recovering its state at one moment discloses regroup beacons only from that moment forward, never the group's past. It is a forward-only, clock-indexed hash ratchet, not a function of a stored stable secret. Let c = floor(unixtime / BUCKET) be a coarse time bucket (BUCKET on the order of hours) and c_form the bucket at group formation (a non-secret group constant). At formation each member seeds the ratchet from a dedicated recovery secret, then zeroizes the root and never persists it:

rs_root      = KDF(group_recovery_secret, "plenum-recovery-v1")   // transient, zeroized after seeding
rs_0         = rs_root
rs_k         = H(rs_{k-1})            // one-way step, k = c - c_form (buckets since formation)
recovery_queue = KDF(rs_k, "recovery-queue")

Only the current ratchet state rs_k is persisted (inside the encrypted backup blob), overwritten forward as buckets pass; rs_root and all earlier states are discarded. Every member reaches the identical rs_k because the chain is indexed by absolute elapsed buckets, not by activity: a returning member forward-hashes from whatever state it last stored up to the current bucket, and to tolerate clock drift it derives the queue addresses for buckets {k-1, k, k+1} the same way and scans all three, never needing to invert H.

What this buys: backward secrecy. A recovery state recovered at bucket k (by decrypting a captured blob, or from a stale leaked off-site copy) yields the recovery queue for buckets >= k only. Because H is one-way and rs_root was destroyed, it cannot reconstruct any earlier state, so it cannot locate the group's prior regroup traffic on archived servers. The retroactive-archive scan, the sharp edge of a stable secret-derived address, is eliminated.

What it does not claim. A currently compromised member endpoint holds the live ratchet state and can compute the recovery queue forward until the next membership change. This is the endpoint-compromise case already out of scope (Appendix C), and it is self-limiting: a membership change is a brand-new group with a fresh recovery root (6.1), so the forward window is bounded by the current group's lifetime, not open-ended. The recovery queue carries only the rendezvous beacon; the moment enough members meet there, the group runs an MLS commit, re-establishes a fresh epoch, and resumes on the forward-secret operational queues, so ongoing coordination never lives on the recovery queue. Because regroup is rare and this queue's traffic is sparse, it carries the same cover traffic and size-bucketing as the operational path (4.3), the per-message proof-of-work stamp, and a short bucket. A group whose mere existence or regroup cadence is sensitive may disable the recovery queue entirely by policy and route total-outage regroup over the out-of-band channel used for the initial invite (5.1), removing even the forward-only beacon at the cost of a manual regroup step.

Backstop. The shared on-chain Monero multisig address is a permanent anchor that every member can re-derive from backup. If even the rendezvous substrate fails, members fall back to out-of-band contact, the same channel used for the initial invite (5.1).

5. Forming a group

A group comes into being through a one-time, coordinated ceremony. This section covers how it is set up and how the members are invited and verified.

5.1 Initial setup: the master and the setup ceremony

Creating a group is a one-time ceremony coordinated by a master (the initiator), whoever decides to start a wallet and pulls the others in. The master chooses the parameters (m-of-n and who the members are), creates the MLS group, invites each member, and collects their MLS KeyPackages. He then drives the FROST distributed key generation (DKG).

The FROST key generation. The wallet is built with a FROST distributed key generation (DKG): every member generates their secret share locally, it never leaves their device, and the group public key, and the Monero address derived from it, is deterministic from all members' contributions. The DKG is a fixed two-round exchange for any m-of-n:

  1. commit. Each member publishes a commitment to its contribution.
  2. share. Each member distributes verifiable shares against those commitments; every member verifies them and derives the identical group key.

This is two rounds regardless of the threshold, and each signer ends with a single secret share rather than the combinatorial set Monero's native multisig would require (7.1).

The master's job is sequencing and relay, nothing more. Each round is a barrier: the master waits until all N members have submitted that round's payload, then relays the bundle and opens the next round. Nobody advances early. The payloads travel as a dedicated "setup round" message type through the group channel. The round-one commitments are a broadcast every member sees identically, so no member can equivocate on its public commitment; the round-two shares (encrypted per recipient) are each verified against that broadcast commitment, with the all-N address gate as the final backstop. Equivocation is blocked by the commitment broadcast plus per-share verification, not by assuming every message is a uniform broadcast. The master never sees any secret share; each share is generated inside its owner's client.

Final address confirmation. When the wallets report ready, every member independently reports the resulting multisig address. The ceremony is valid only when all N report the identical address. A mismatch means stale data or tampering, and the ceremony aborts. Combined with MLS sender authentication (which prevents substituting a member's blob), this is what makes a malicious or buggy master detectable rather than dangerous.

Stalls and dropouts. The setup ceremony has no hard timeout (a different thing from the trade-deadline timeouts a vendor policy may put on a spend, which are a separate, later lifecycle event): setup is a deliberate, coordinated act, so a member who is slow to respond is simply reminded and re-invited by the master, not timed out. A permanent dropout forces a restart of the DKG: a key generation cannot swap a participant mid-flow, so if a member leaves before completion the master aborts and re-runs it with the replacement set. There is no partial resume, but the DKG is only two rounds, so a restart is cheap.

The master is a bootstrap role, not a permanent authority. Once the ceremony completes he is one of the n signers with no extra power: he cannot spend alone, cannot evict anyone, and cannot read more than any other member. He holds no special key afterward; the group is leaderless and symmetric. During the ceremony, before the group secret exists, every participant including the master meets at the ceremony queues derived from a one-time secret in the invite (4.5), each only connecting out to the SMP servers. The master coordinates by pushing and pulling at those queues like everyone else; he hosts no reachable service and is no delivery point. KeyPackages and round messages flow through those queues until the group is fully established.

5.2 Onboarding and invitation

A group is created by its initiator, the same person who acts as the bootstrap master (5.1). In the client they choose the threshold (m-of-n) and the member set, which creates the MLS group.

Invitations are deliberately out-of-band. Plenum has no directory and no public registration, so the trust that a given person belongs in the group must come from outside the system: the initiator reaches each prospective member over a channel they already trust (in person, an existing secure messenger) and passes a bootstrap invite. The invite carries only what is needed to reach the ceremony: a ceremony identifier and a one-time ceremony secret from which the shared ceremony rendezvous tag is derived (5.1, 4.5). There is no delivery point to address; every participant meets at that derived tag. It is not a credential and grants nothing on its own; it just tells the client where to show up.

On accepting, each invited member's client generates its long-term MLS credential (its member_id, 4.5) and a KeyPackage locally, and returns the KeyPackage to the master, who adds it to the MLS group through the MLS Add and Welcome handshake. From there the setup ceremony (5.1) runs.

Verification. Two layers guard against the master adding the wrong key for a member, whether by mistake or to slip in an impostor. First, members compare their MLS credential fingerprints over the same out-of-band channel used for the invite, the standard way to bind a key to a real person. Second, the all-N address-confirmation gate (5.1) is a backstop: a substituted or wrong member key changes the resulting multisig address, so the ceremony completes only when all N independently report the identical address. A tampered member set therefore fails closed instead of producing a usable wallet. The fingerprint comparison is a mandatory gate, not an optional nicety: the master accepts a member's KeyPackage only once its credential fingerprint matches the value agreed out of band for that person, so a substituted key is rejected before the DKG rather than only inferred afterward from a wrong address. The address gate proves the group computed one consistent address; it cannot prove the right people are in the group, which is what the fingerprint match establishes. In the automated escrow flow, where no in-person meeting happens, this takes the form of a short safety-number each party confirms in the client against what the vendor displays before the DKG starts.

6. Backup and recovery

Multisig is the hard case for backup, because the key material is not a normal seed phrase. This section covers how Plenum backs a wallet up, how it is restored, and how the interface keeps the user from misunderstanding either.

6.1 Backup strategy

Goal: every wallet is recoverable from a backup the user controls. Monero single-sig is easy; Monero multisig is the hard case, and that is where Plenum supplies its own backup layer.

Two cases:

  1. Ordinary Monero single-sig (not a Plenum wallet, shown only for contrast): a Polyseed or legacy 25-word seed derives everything, and nothing special is needed. A Plenum wallet is never this case.

  2. Monero multisig (the critical case): the key material is not derivable from the normal 25-word seed. Each participant holds a FROST key share, generated during the DKG. For a 3-of-5, at most 2 losses are tolerable. A normal seed phrase does not restore a threshold wallet, which is exactly why ordinary users lose funds.

    Here Plenum supplies its own backup layer. The backup is a single encrypted blob: the complete wallet state including the member's FROST key share and personal data (address labels and the like), encrypted client-side before it ever leaves the device under a key derived from the user's own seed through a memory-hard KDF (Argon2id with high parameters), so that even though every fellow member is handed a copy of the ciphertext, brute-forcing a captured blob offline stays uneconomic. The seed is the user's single backup root: it derives the key that encrypts this blob. Neither the FROST share (produced in the DKG) nor the member's per-group MLS identity (4.5, generated fresh for each group) is derived from the seed, so both live inside the blob; the seed opens any surviving copy to recover them. That one blob is replicated to three kinds of destination for redundancy, and the user can enable any or all of them:

    • Local (always on). The blob lives with the user, on their own hardware and storage. This is the baseline and depends on nothing but the user's own seed.
    • S3-compatible remote stores (off-site). One or more S3-compatible endpoints (self-hosted MinIO, a VPS, or a commercial bucket). The operator only ever sees ciphertext, so an untrusted or commercial bucket is safe. Multiple endpoints can run at once.
    • The other group members (over the channel). Each member also stores a copy of every other member's blob, with store-and-forward holding it for anyone offline. The members see ciphertext only, so this is redundant off-device storage, not shared access.

    All three hold the same ciphertext, which only the user's own seed can open. Because a fellow member is exactly the party handed the ciphertext, the backup key is memory-hardened (above) and members are advised to choose independent off-site stores; the client flags it when two members of one group configure the same S3 endpoint, which would otherwise let one provider hold a threshold of blobs. The model is durability through redundancy: a destroyed device is covered by the off-site and member-held copies, and restoring the wallet needs only the user's own seed plus any surviving copy (the FROST key share and per-group identity inside the blob then restore the wallet non-interactively, see restore). It does not protect against a user losing their seed; that is out of scope by design.

    Membership change means a new, independent group. Although FROST supports resharing a key to a new signer set, Plenum deliberately does not use it: there is no in-place edit of the signer set and no migration path between groups. Changing who signs means the users create a brand-new wallet through a fresh DKG (5.1): a new MLS group, new keys, new backups, with no protocol-level link to the old one. Whether and how funds move from the old wallet to the new one is an ordinary spend the users perform themselves while the old threshold still holds; Plenum does not automate it and records no relationship between the two groups. The old group and its backups simply become defunct. Old blobs are ciphertext only their owner can open and back up a wallet the users have emptied, so they are harmless whether kept or not; each user deletes their own local and S3 copies, and lets the group go, if and when they choose. There is deliberately no epoch chain or pointer tying a new group to a previous one. The sole exception is opt-in: an auditable group (8) may carry its public identity forward with a succession certificate, which the old group must sign while still operational. That certificate is a deliberate public link in auditable mode only; private groups have none.

6.2 Restore workflow

Restore mirrors setup. Three cases, by severity:

  1. Member lost a device, still has their seed. The member fetches their encrypted blob from whichever copy survived (the local one, an S3 store, or a fellow member over the channel) and decrypts it with the key derived from their seed. Restore is non-interactive from the FROST key share inside, so no other member, and no master, has to participate in the decryption. The member then re-joins the MLS group by an MLS external commit: using the group's current public GroupInfo (kept in the backup and refreshed from the channel if stale), the member re-adds itself and re-keys in one step, without any other member or the master acting.

  2. Member lost their seed too: that member's share is gone. Every copy of the blob is now unopenable, so this member cannot recover their own key material. The wallet's funds are still safe as long as the threshold of other members survives. To restore redundancy, the surviving signers re-run the DKG (5.1) to form a new group (dropping the lost member or onboarding a replacement) and sweep the funds across.

  3. Catastrophic loss beyond tolerance: funds frozen. If more signers lose their key material than the threshold tolerates (for example more than 2 in a 3-of-5), the funds cannot be moved at all, because sweeping to a new multisig itself needs the old threshold. This is the hard limit of m-of-n; Plenum cannot work around it. The mitigation is the redundant three-destination backup above: it makes a single member's total loss recoverable and reduces the chance that enough members lose their material simultaneously to break the threshold.

Master vs no-master. Restoring access to an existing wallet (cases 1 and 2) never needs a master. Only rebuilding the multisig itself (case 3, with changed membership) re-invokes the master-coordinated ceremony. So the privileged-looking coordination reappears only when the group structure genuinely changes, never for ordinary recovery.

6.3 Recovery UX

The backup model (6.1) only protects the user if they grasp two facts, so the interface makes both unmistakable instead of burying them in settings.

First, only the user's own seed opens the backup. The seed is the single backup root: it derives the key the blob is encrypted under (6.1), and that blob in turn carries the per-group identity and the FROST share. Any local password the client offers is only an optional lock on the running app, may be left empty, never leaves the device, and is no part of the backup encryption or recovery; losing it costs nothing as long as the seed survives. The three destinations (local, off-site S3, fellow members) all hold the same ciphertext, and the client presents them as redundancy, not as custodians: it states plainly that members and remote stores keep a copy they cannot read, so the user never mistakes "my backup is with the group" for "the group can recover it for me." At setup the client shows the seed as the one thing the user must record themselves, noting that it opens any surviving backup copy, which reconstitutes the wallet, the per-group identity, and all personal data, and that the FROST key share inside that copy is what restores a threshold wallet where a normal 25-word seed cannot.

Second, losing the seed is unrecoverable, and the interface says so at the moment it is set, not in fine print afterward. The redundancy across destinations is framed as protection against a lost device, not against a forgotten secret.

Restore presents the surviving copies it can find (the local one, each configured S3 store, each reachable member) and lets the user pull from any of them, then decrypt locally with their seed. The flow mirrors restore (6.2) and, in the common case, never asks another member to take part.

7. Operational properties

Three cross-cutting properties: how the design scales, how it resists abuse, and what the user actually runs.

7.1 Group size and performance

Neither layer imposes a combinatorial cost. MLS/TreeKEM scales logarithmically: adding, removing, or updating a member is an O(log n) operation in message size, so the encryption layer would handle hundreds of members without strain. FROST is t-of-n with a single secret share per signer and a fixed two-round DKG regardless of the threshold (5.1), so it has none of the blow-up that Monero's native multisig suffers, where a balanced m-of-n would hand each signer C(N - 1, M - 1) key shares (6 at 3-of-5, 70 at 5-of-9, 252 at 6-of-11). Choosing FROST is what removes that ceiling.

Group size is therefore a usability and trust choice, not a cryptographic one. A Plenum group is a treasury's signer set, so it stays small (typically 2-of-3 to about 3-of-5) because that is what shared custody looks like, not because larger or balanced thresholds would be expensive. MLS re-keys on every Commit, and members also send periodic Update commits for forward secrecy independent of membership; a signer-set change is a brand-new group (6.1), not an in-group re-key. Re-keying is cheap at this scale (O(log n)), and the higher-frequency traffic is the social room, trivial too. The backup's size is dominated by the wallet state (outputs, key images, labels), which grows with usage rather than with the number of signers, since each signer stores just one FROST share. Size here is the per-group signer set; an operator may run many such small groups in parallel, which is a question of instance count, not of group size. Performance is not a limiting factor.

7.2 Spam and abuse resistance

A Plenum group is closed, which removes most of the surface. Membership equals the n signers (3.2), every message is sender-authenticated by MLS, and there is no public join endpoint: invitations are out-of-band (5.1) and the master only accepts KeyPackages from members it invited. An outsider therefore cannot post to the social room, the coordination channel, or the backup store at all. A member who floods or misbehaves is not a cryptographic problem but a social one: they are one of the signers, and the remedy is to re-run setup without them (6.1), the same action as any membership change.

The one shared surface an outsider can reach is the delivery substrate itself. To push to a member's queue (4.4) a party needs that queue's current epoch-rotated address, which is derived from the group secret and never published, so an outsider has nothing to flood unless an address leaks. Even then the exposure is bounded by four things: a proof-of-work stamp required per pushed message, which makes bulk flooding expensive for the sender, the SMP servers' own rate limits, per-member quotas on the store-and-forward layer, and the fact that a leaked address dies at the next epoch rotation. None of this is novel; it is the standard closed-group plus work-gated-substrate model, and it holds because Plenum never exposes an open, unauthenticated endpoint.

7.3 Client surface

Plenum ships as a desktop wallet with a graphical interface as the primary client. The same application also runs in a headless mode that exposes two programmatic interfaces: a REST API and an MCP API. The GUI covers the ordinary human user (create a group, approve a spend, manage backups); the headless mode lets the wallet be driven without a screen, by a script, a remote operator, or an AI agent acting under human approval. Both modes are the same binary over the same wallet core and group channel, so a headless instance is a full participant in the multisig and the MLS group, not a reduced client.

A mobile wallet for Android follows later, after the desktop client ships; it is the second phase, not part of the first release. iOS is out of scope: its sideloading and background-networking restrictions are hostile to an anonymity-network wallet, and the platform's review and distribution model conflicts with the project's free-software stance. Android allows direct distribution (APK, F-Droid) and the background connectivity the transport needs.

All clients are dedicated Plenum applications built on a maintained MLS implementation (4.2), not a fork of an existing chat client.

8. Auditable mode (optional)

By default a group is private: it has no persistent public identity and meets only on epoch-rotated, group-derived queues with no stable wire identifier (4). Some groups eventually want the opposite: to announce their existence, sign public statements, or prove what they hold. Plenum offers this as an explicit second mode, auditable, that a group can switch into. Private is the floor; auditable is a disclosure layer on top.

The switch is unanimous; attestations afterward are m-of-n. Going from private to auditable requires n-of-n consensus: every member must agree, because publicity affects all of them and is effectively irreversible (anything published stays public). It is not a setting one member flips, and any single member can veto it. As part of the switch the group defines its public identity, an alias under a dedicated key (below). Once auditable, the individual attestations (signing a statement, producing a reserve proof) run at the normal m-of-n threshold, since the group has already consented unanimously to being public; requiring n-of-n per attestation would let one absent member block every statement. A later switch back to private is an m-of-n decision that stops new attestations, though anything already published stays out.

Auditable mode adds three public capabilities:

  1. Persistent identity. Going auditable, the group picks a public alias and derives a dedicated identity key for it, separate from every internal key, and publishes the key as its long-lived handle. Because a membership change normally produces a brand-new group with a new key (6.1), the identity is carried across by a succession certificate: the old group threshold-signs an endorsement of the new identity key, forming a verifiable chain that survives membership changes without resharing. The old group must sign this endorsement while it is still operational, before it goes defunct: a dissolved group can no longer endorse a successor, so the certificate is produced as a mandatory step of the transition. Because endorsing a successor is as consequential as going public in the first place, the succession endorsement requires the full n-of-n, not m-of-n: no subset can hand the public brand to an attacker-controlled key. Succession certificates are published to a public, append-only log, so a covert hijack is at least immediately visible to any verifier following the chain.
  2. Threshold-signed statements. The group can sign an arbitrary message m-of-n, producing a single standard signature anyone can verify against the published identity key (Appendix A, attest.*). This is FROST's native function, needs no on-chain action, and works on plain Schnorr without the Monero-specific signing path.
  3. Threshold proof of reserves. The group can prove, m-of-n, that it controls at least a stated amount. The attestation reveals only that minimum balance, not which outputs back it nor where they came from. This requires a zero-knowledge proof of reserves rather than Monero's native reserve proof (which would reveal the specific outputs) or a published view key (which would expose all incoming activity). A threshold zero-knowledge proof of reserves over a wallet with no single spend key is the heaviest cryptographic component here: a research-grade primitive, not off-the-shelf and not yet available, expected to mature alongside the chain's own full-chain proofs. Statement signing, by contrast, is available today; the reserve proof is the one auditable-mode capability that is still a research item rather than a finished feature.

Compartmentalization keeps auditable from weakening private operation. The public identity key is a separate key, distinct from the wallet spend key, the MLS credentials, and the ephemeral transport and rendezvous keys. Publishing it, signing under it, or proving reserves discloses only what the threshold chose: it does not reveal the spend key, does not expose the rendezvous tag or members' network identities, and does not by itself link the group's on-chain address (a reserve proof links only the outputs it names). The default-private machinery (4) keeps running underneath, unchanged. By construction, auditable mode cannot leak the private layer beyond what the group explicitly publishes.

Appendix A: Message schema

Two classes of message travel in a group. The first is MLS handshake, provided by the MLS protocol itself; Plenum does not define it, only uses it. The second is Plenum application messages, carried as MLS application payloads (already end-to-end encrypted and sender-authenticated by MLS).

MLS handshake (from the protocol, listed for completeness):

Common envelope (every Plenum application message):

Plenum application message types:

Type Purpose Key fields
setup.round One FROST DKG round payload (5.1) ceremony_id, phase (commit/share), payload (DKG round data)
setup.address_confirm Final all-N address check (5.1) ceremony_id, multisig_address
chat.message Social-room text body
spend.proposal Propose an outgoing transaction proposal_id, unsigned_tx, amount and destination (advisory, see note), optional note
spend.commit A signer's FROST nonce commitment for a proposal (signing round 1) proposal_id, nonce_commitment
spend.signature A signer's FROST partial signature (signing round 2) proposal_id, partial_sig
spend.finalized Completed and broadcast transaction proposal_id, txid
backup.blob Announce the owner's encrypted backup to others (6.1) owner_id, version, ciphertext_ref (manifest pointing at the off-channel stores), checksum
backup.request / backup.deliver Ask for a stored blob back / return it owner_id, version
store_forward.envelope Wrap a message held for an offline member, redelivered on reconnect recipient_id, inner, deposited_at (a coarse epoch bucket, not a wall-clock time)
cover.traffic Dummy padding posted on a randomized schedule to blur signing-round timing (4.3) nonce (random, discarded on receipt)
mode.switch Propose and approve a mode change (8); going auditable requires n-of-n and sets the alias here proposal_id, target_mode, alias, identity_pubkey
attest.proposal Propose an m-of-n public attestation to publish: a signed statement or a reserve proof (8) attest_id, kind (statement/reserve_proof), payload
attest.signature A signer's partial signature toward an attestation (8) attest_id, partial_sig

member_id is the hash of the member's long-term MLS credential public key (4.5), which maps to the member's Monero signer position from setup. The amount and destination on spend.proposal are advisory display hints only: each approver independently rebuilds the unsigned transaction from the proposal and verifies the received unsigned_tx matches, then displays the destination and amount parsed from that verified transaction, never the self-declared fields. A mismatch aborts the approval (fail closed). A spend is coordinated per proposal by its proposer (a transient role, no standing power): the first m members to approve form the signing set, a signer dropping mid-round restarts that round with fresh nonces, and concurrent proposals are resolved by first-broadcast-wins, so at most one spends the shared inputs. Ciphertext in backup.blob is opaque to every member but the owner, consistent with the backup model in 6.1.

Appendix B: Transport integration

Each member reaches the SMP servers (4.4) over one anonymity network, Tor or Nym, chosen per member (4.3). Either way the client only connects out; nothing is hosted, unless a group chooses to self-host its own SMP server.

Reliability notes: the Nym path is younger, higher-latency, and needs paid bandwidth credentials; both paths lean on SMP server availability, smoothed by spreading a group's queues across several servers and by the store-and-forward the SMP servers provide.

Appendix C: Threat model

This consolidates the adversaries named across the document and states, per adversary, what Plenum protects against and what it does not. It is a design-time threat model, not a substitute for an independent security audit.

Adversaries and coverage

The metadata leak the delivery design avoids

If delivery used stable identities and standing addressed messages (the naive substrate), a server or observer would build a map of the group without decrypting anything. Plenum's delivery (4.4) is built to deny each line of that map.

Function Naive metadata leak Plenum countermeasure
Setup ceremony N stable keys exchange round-timed messages: a fingerprint of group formation, size, and member linkage Epoch-rotated queues spread across servers (no stable identifier, no single server sees the whole group)
Coordination and spend Fan-out in the same key set per spend reveals activity and spend cadence, and is timing-correlatable to the Monero chain Epoch-rotated queues, jitter and cover traffic; Nym mixing breaks the chain-timing correlation (Tor does not)
Social chat Recurring traffic between the same keys confirms the social graph Epoch-rotated queues (no stable sender to graph)
Backup and store-forward Blob sizes, who-stores-for-whom (the trust graph), and offline status Ciphertext only, blobs padded to size buckets, store-and-forward across spread servers

Standing assumptions

Residual risks, stated plainly