Separate from my proposal for key transparency for the Fediverse (which I’ve certainly blogged about a lot), the W3C has been working on building out end-to-end encryption (E2EE) for ActivityPub.
The two projects are mostly being developed independent of each other, though connecting the two should be straightforward.
As I prepare to tie up the loose ends and call my side of the work “feature complete” and consider tagging a major version 1.0.0 for the specification and reference implementations, I thought it would be useful to lay out the work that needs to be done in order to get this over the finish line–in part, because this is where most technical folks can begin to meaningfully contribute without needing security or cryptography expertise.
Unlike most of my blog posts (which are intended to be what some bloggers call “evergreen”), I fully intend for this one to be less useful over time, as the work gets done.
To make the most sense, I’m going to work backwards from the desired end state, delving recursively into prerequisites of each unit of work necessary, and then follow it up with a roadmap that should have no surprises if you read the preceding prose.

Working Backwards
This is a complicated effort, so I think it’s best to start by distilling the desired end state into three distinct goals.
Fundamental Goal: Fediverse users should be able to send each other end-to-end encrypted messages, which may include attachments. This must efficiently support group messages, not just 1:1 messaging. This is currently being implemented with Emissary and Bonfire, built on a protocol called Messaging Layer Security (MLS, RFC 9420).
Security Goal: Users should be able to know that the end-to-end encryption is being performed correctly, and with the correct encapsulation keys.
To that end, Each encapsulation key (which is shipped in what MLS calls KeyPackages) must be signed, client-side, by the user (using an asymmetric digital signature algorithm).
Authenticity Goal: The signing keys must be verifiably controlled by the user, and anyone must be able to verify this property. This verification must not rely on a central authority.
The Authenticity Goal is where key transparency comes in. By providing an append-only cryptographic transparency log of which Actor (in ActivityPub parlance) controls which signing keys, you can build a decentralized root of trust. This is where my focus has been for the past several years.
These goals build on each other:
- Without satisfying the Fundamental Goal, none of this work has any real pay-off to end users.
- Without satisfying the Security Goal, the end-to-end encryption must come with a giant fucking asterisk that nobody wants.
- Without satisfying the Authenticity Goal, Fediverse clients that wish to support E2EE will resort to Safety Numbers of Key Fingerprinting–techniques that even professional cryptographers I respect do not bother themselves with, and therefore not a realistic expectation for most people either.
Let’s first discuss each of these three work streams as separately as possible.
Why Do Something Rather Than Nothing?
Note: This was added after the blog post was initially published because it’s important context.
The status quo is as follows:
- Direct Messages today do not use end-to-end encryption
- Regardless of jurisdiction, storing sensitive messages and attachments as plaintext is legally perilous for Fediverse instance hosts
- The EU codifying ChatControl 1.0 into law is also noteworthy here
This may come as a surprise to some folks, but sending nude images or videos is kind of a normal thing that many adults want to do (hopefully with consenting recipients).
But if you have a large repository of such content, suddenly these instances becomes a juicy target for sextortion or revenge porn. This is also a risk if one of your instance administrators goes rogue, or is secretly evil to begin with.
End-to-end encryption mitigates most of this risk by virtue of not having any plaintext stored on any Fediverse instance servers to begin with.
For more on threat modeling, see my previous blog post.
Art: MarleyTanukiE2EE with ActivityPub
The Fundamental Goal (as I defined above) is being worked on by the SWICG’s ActivityPub E2EE project team (part of W3C). Most of their work can be surmised by reading the draft specification and the issue tracker on GitHub.
In order to achieve this goal, they (obviously) need MLS implementations in each of the programming languages relevant to end user Fediverse clients.
For example, ts-mls is a TypeScript implementation of MLS that supports post-quantum cryptography, and OpenMLS is a Rust implementation that ts-mls is being tested against for interoperability.
There is currently an Internet Draft for post-quantum MLS being discussed on the IETF MLS mailing list. The latest draft includes a registration for a ciphersuite that I requested (and recommended to the ActivityPub E2EE project).
As I noted in my previous blog post, consistent message ordering is the thorny issue to tackle for making MLS distributed. The previously linked RFC draft discusses some approaches for solving this problem at scale.
Satisfying the Security Goal
Fediverse clients that adopt E2EE will need the ability to authenticate KeyPackages.
This is the simplest part of the whole ordeal:
- Client software must manage secret key material for digital signature algorithms (e.g., Ed25519, ML-DSA).
- Client software that generates KeyPackages must include a valid digital signature, using the aforementioned secret keys with the correct algorithms.
Every secret key comes with a corresponding public key. To satisfy the security goal, one needs a mechanism for ensuring they have the correct public key for each of the other users. See: the Authenticity Goal.
There is very little to do in this work stream, as it mostly requires gluing the other two work streams together in a manner that isn’t prone to algorithm confusion or key substitution attacks.

Fediverse-Scale Authenticity
There are several schools of thought on how to authenticate users’ identity public keys in a federated system. It’s important to understand the kaleidoscope of possible solutions before rolling up your sleeves and getting dirty.
Here are three of many possible ways to tackle authenticity at Fediverse scale:
- Certificate Authorities.
This is what we have for TLS certificates today. It’s a known pattern, but is also centralized and prone to government and corporate corruption. - Key Fingerprinting.
Discussed in activitypub-e2ee#43, the idea is to create a deterministic fingerprint of a users’ public key so that users can verify them in person or over some existing trusted channel. - Key Transparency.
I wrote activitypub-e2ee#35 to propose this as a solution.
I generally do not think Certificate Authorities is a good fit for the social web. I don’t have a specific technical argument here, it just feels a bit too Papers Please for the Fediverse, and we could all do with less of those vibes.
Regarding the two left, key fingerprinting techniques put all of the responsibility on the end user to not get tricked, while key transparency is more of a herd immunity oriented solution that can run in the background, raising the floor without touching the ceiling.
The two aren’t mutually exclusive. Client apps could implement a sort of Traffic Light styled protocol. Something like this:
GREEN: Both of the following statements are true.
- The user has verified the key fingerprint / safety number, scanned a QR code in person, or otherwise manually performed some verification step
- The public key can be verified independently from the key transparency log. It has not been revoked.
AMBER: One mechanism has been satisfied (key transparency, manual public key verification), while the other is absent.
- Users that refrain from manual actions will get used to seeing a lot of amber.
RED: Warn the end user (but be careful about it)
- If neither mechanism can be satisfied (a random stranger sent a DM without publishing their public key into the transparency log), the user should be informed.
- If the user’s public key was revoked (due to an account compromise or recovery action), or a cryptographic error occurred, then whatever trust the end user had in their communications cannot be extended via cryptography and this should be clearly explained to them.
This is not the only way to reconcile the two mechanisms, and there might be better ones to consider. I am certainly not a User Experience expert, and developers should consult one before shipping anything.
Additionally, transparency (heh) about the limitations of these mechanisms is paramount.
- Key transparency involves a proof-of-possession for public keys (and handles rotation automatically).
- Manual verification is a local trust assertion for a specific public key (new keys must be manually re-verified if identity keys ever rotate).
- Neither mechanism proves that the encryption is secure; that’s handled by a different layer.
- Neither mechanism nor the E2EE proves that the endpoint device is secure. Your conversation might be private, but that doesn’t stop the other people from being scoundrels.
The word “trust” is often misused in a hand-wavy fashion to mean one or all of: “cryptographic identity verification”, “authenticity”, “confidentiality”, and “social trust”. It is imperative that we (developers and users) develop a shared vocabulary for talking about these topics to minimize confusion.
I have opinions, but I don’t have the answers. This will need to be a conversation.
All that being said, I’ve been working since 2024 on a key transparency-based solution for the Authenticity Goal, so that’s what I have the most up-to-date knowledge on.
Why Not Just Shove The Public Key Into Your Profile And Call It A Day?
Note: This was added after the blog post was initially published because it answers a question I thought was obvious.
As mentioned in my earlier amendment to this blog post, part of the threat model for this sort of solution is rogue server administrators.
If you just shove your Public Key into your profile metadata, what’s stopping your instance operators from replacing that public key with another one? And how will other people detect it?
The work on Key Transparency only controls the public counterpart of a long-term keypair used only for digital signatures.
These aren’t encapsulation keys (a.k.a., asymmetric or “public key encryption” keys). Encapsulation keys belong to the MLS KeyPackages, which are NOT planned to ever be logged in a key transparency system. The KeyPackages will be signed by the keypair whose public component is stored, however.
If this sounds strange to you, you should know that’s how TLS 1.3 works too!
Signing ephemeral encapsulation keys is how you preserve forward secrecy while still binding the whole shebang to some identity key.
In TLS’s case, it’s the certificate. In our case, it’s the transparency logs.
Look up “Authenticated Key Exchanges” sometime. One of the oldest posts on this blog covered them, but that was more than 6 years ago.

The Bridges Yet To Cross
Okay, if you’ve read everything up to this point, you should be up-to-speed on what the goals are and why those goals matter.
There are infinite possible other goals we could pursue, truthfully, but I believe this is the framing that helps us deliver the best result for the Fediverse as soon as possible.

(Yes, I play Deltarune lol :D)
Now let’s talk about what needs to happen to get there.
The Road To The Fundamental Goal
In order to have end-to-end encryption for ActivityPub, we need clients to support MLS.
This requires having open source libraries that implement MLS in the programming languages relevant to the existing Fediverse client software. Each of these open source libraries, in turn, need to support at least one ciphersuite in common.
I recommended two post-quantum ciphersuites to SCIWG, and the latest mls-pq-ciphersuites draft includes both.
Before any thorny technical discussions are even considered, the table stakes for delivering this work is:
- More MLS implementations in more languages
- Rough consensus (in the IETF sense) on which ciphersuites to support
- More security assurance for those implementations
But before we can cross that bridge, there are several technical decisions that need to be resolved.
- Metadata and Consistent Commit Ordering
- Key commitment / message franking / abuse reporting
- How to handle large attachments
- Message backups / multi-device / virtual clients
- The “virtual clients” RFC draft being discussed by the MLS working group might solve this well enough.
- Essentially, MLS leaf nodes can secretly be its own secret sub-tree. You can use this to support multiple devices where each device acts as a single participant in the larger subtree.
- This subtree work might also be useful for hiding some plaintext metadata from the actual Fediverse instances, but that’s still unclear.
- Two-party profiles
- See: two-party profile RFC draft
- This might be useful for reactions or “read receipts”, should clients choose to support these
When discussing this privately, several other concerns were brought up, but they’re already mitigated by the other goals outlined in this blog post, so I’d rather focus folks’ attention on the unresolved / open problems.
How You Can Help
The discussions linked in the above list on mailing lists, issue trackers, and forums are the best places for technical experts to get started.
Not just cryptography and security experts, either. Some of these problems are an advanced application of basic computer science and networking principles, so I implore everyone with technical backgrounds to participate, even if it’s not immediately obvious how you can help.
Open source software developers might want to implement support for MLS and the various extensions currently being discussed. I implore you to join the MLS mailing list.
Fediverse users that do not have a technical background should pair up with technical experts: Give feedback on things that technical people might overlook.
- Do these solutions meet the bar for accessibility? (This cannot be an afterthought!)
- Is the documentation clear enough for you?
- Can you actually use the software they’re developing?
- Does the security stuff sound like black magic, or can you make sense of it?
The desired end state of this work is to empower everyone, not just turbo-nerds that can tell you off-hand, without needing to consult reference material, the word sizes and number of rounds for SHA-256 and SHA-512.

The Road To The Authenticity Goal
Without literally restating my specification for key transparency in the Fediverse, the important takeaways are how the pieces fit together.
- Protocol Messages will originate client-side, pass through their instance software, and then get submitted to a Public Key Directory.
- Clients will encrypt Protocol Messages using HPKE, using the Directory’s advertised public key.
- Instances will, after verifying that the message is for the currently authenticated user, sign the request using HTTP Message Signatures and pass the signed request onto the directory as a Direct Message.
HTTP Message Signatures
Regardless of the other design considerations, this means that libraries that support HTTP Message Signatures (RFC 9421) must also support the signature algorithm required by the Public Key Directory project: ML-DSA-44, which is a post-quantum secure algorithm.
I recently submitted a specification to C2SP that defines the ML-DSA algorithms, and some test vectors, for use with HTTP Message Signatures. While I was drafting this blog post, IANA accepted them onto the HTTP Message Signature registry.
With this out of the way, two things need to happen immediately:
- RFC 9421 libraries need to be updated to support the
ml-dsa-44signature algorithm. - More Fediverse software needs to adopt FEP-521a to support multiple signing keys per Fediverse actor.
(The pkd-crypto library provides an HttpSignature class that supports ml-dsa-44, if you need a target to test against.)
Since FEP-521a depends on the W3C Controlled Identifiers specification for encoding public keys, the authors of that doc will need to release a new version that adds support for ML-DSA with the existing support for other algorithms.
Once that is done, there should be no other specification-level blockers for starting work on RFC 9421 / httpsig-pq / FEP-521a work across other ActivityPub-enabled software today.
If your programming language’s cryptography module doesn’t already provide ML-DSA today, well, there’s no time like the present to starting work on getting that solved. Wrapping RustCrypto’s ml-dsa crate is a fine option too.
Fediverse Auxiliary Service Provider
In December, I started a discussion to write a FASP to support Key Transparency. Despite a few upvotes, there was no response.
I don’t know who or how to prod the folks responsible to get the discussion moving. A FASP is probably the best way to integrate key transparency here, but I’m also open to other avenues.

Instance and Client-Side Software
I already wrote a reference client-side library for the Public Key Directory project in PHP.
I’m currently working on writing a separate Rust implementation that other clients can compile to WebAssembly or wrap with FFI in order to support a wider range of programming languages.
The current plan is to develop it using hax and use Kani to prove its correctness. I take software assurance seriously.
Don’t let that effort stop you from writing your own, should you decide to do so. We have specifications and a reference implementation. You should be able to build your own client.
If you find it difficult, that’s a bug that I should fix!
The Road To The Security Goal
Put simply: Completing the two other workstreams, and uniting the work in the final implementation, will suffice to satisfy the Security Goal.
MLS KeyPackages have an existing signature field, but using the public keys vended by the Public Key Directory project (which only allows ML-DSA-44 as of version 1) would constrain everyone to using a smaller set of ciphersuites.
To avoid that downside, I recommended making this a detached, separate signature field from what’s internal to MLS itself. This prevents the key transparency abstraction from leaking into the MLS abstraction in undesirable ways.
However, this will likely be addressed around the time as the final section of this blog post: Adoption.

Adoption of The Work
All of the work preceding this section involved technical specifications, software development, and discussions with many expert stakeholders involved.
If anyone thinks, “if you build it, other people will actually use it,” I’ve got bad news: Adoption requires awareness.
Awareness is a marketing problem.
To not mince words: I am a security engineer that specializes in applied cryptography. I’m about as far from marketing as a technical person can get. Do not ask me for advice about how to market this work in order to drive widespread adoption, I cannot help you.
But also, adoption for privacy technology also requires trust. (Remember that word I discussed earlier?)
Third-Party Assessments Build Trust
In order to establish trustworthy software, we’re going to need third party reviews of all the work discussed above.
- Cryptography audits
- Penetration tests
- Source code review
Despite what Anthropic’s marketing department wants everyone to believe, you cannot effectively outsource this work to an LLM or coding agent and call it a day.
You need actual human expertise (even if any of the experts actually use LLMs as one of their research tools).
Human labor, especially with deep domain expertise involved, is not cheap. Nor should it be!
There are existing non-profit efforts, such as OSTIF or the Sovereign Tech Fund, whose mission is to pay experts to review the designs and implementations of open source software. Whether this work fits well with their mission, or a separate one should instead be established, is something I don’t know the answer to offhand.
But we absolutely should pursue getting this work assessed by third-party experts, and that will require funding. If you want to throw money at a problem and get a high value return from it, this is one area you can do so. (Especially if your employer will match your contributions!)
The other place to funnel money into is, of course, the folks actually developing the open source software that powers the Fediverse, and the folks that run instances for the public benefit.
Closing Thoughts
A careful reader will notice that very little of the work discussed has much to do with cryptography itself. This is intentional:
Most of the ongoing and upcoming work is the sort of thing that nearly anyone reading this blog can pick up in some way.
In fact, the project will be more successful, the more individual contributors decide to jump in starting today.
So let’s build a future where the Fediverse (and all the queer folks that use it) can communicate privately and thrive.
The header art was created by Mebbie, and was commissioned for the sake of the visual pun.
Original post written by Soatok


GREEN: Both of the following statements are true.
AMBER: One mechanism has been satisfied (key transparency, manual public key verification), while the other is absent.
RED: Warn the end user (but be careful about it)
 sticker</p>
<p>” data-large-file=”https://i0.wp.com/soatok.blog/wp-content/uploads/2020/09/soatoktelegrams2020-08.png?fit=512%2C512&ssl=1″ src=”https://i0.wp.com/soatok.blog/wp-content/uploads/2020/09/soatoktelegrams2020-08.png?resize=512%2C512&ssl=1″ alt=”High Paw (high five) sticker” class=”wp-image-1333″ style=”width:256px;height:auto”/><figcaption class=)

Leave a Reply