Autonomous Communicator (AC) Protocol

“Hi, I’m Mark, here’s how you can send a message to me.”

In our last post I announced our incorporation of MLS into Germ, and how MLS underwrites our ability to innovate in identity. Today, I’ll introduce that innovation, our Autonomous Communicator (AC) Protocol. The AC Protocol empowers people to autonomously define identities which they can exchange with others to form relationships for communicating over end-to-end encrypted (E2EE) messaging channels. We designed it to use cryptography to support the ways we naturally form, grow, and dissolve relationships.

In the Germ app, you can create multiple profiles as cards, and can exchange those cards with people to form a connection. People who receive two different profile cards of yours can’t tell they’re both from you, unless you tell them. People must have permission to contact you, which they obtain by exchanging cards with you. If you block or close a connection you make in Germ, the other person can’t send you messages unless you re-exchange cards with them. We at Germ have a limited role in your conversations - we can’t access the content of your cards or messages - our servers merely facilitate the exchange of end-to-end encrypted cards and messages.

The AC Protocol is what makes this possible. This technical blog post describes how it works in Germ today, and sketches a vision of how we plan to empower users thorough the Germ app, acting as the user’s agent in managing their identities and relationships.

The AC Protocol encapsulates our chosen message security protocol, Messaging Layer Security(MLS), under a new identity layer, and above a new transport layer. In doing so, we decouple identity from transport, allowing us to remove identity from message envelopes in transit, and free both identity and transport layers to flexibly evolve identifiers to serve the divergent needs of each.

This protocol is an internet-native reimagination of your contacts — no longer a rolodex of stale information I accumulated about someone else, but a living, cultivated set of connections over E2EE messaging, within which we safely and consensually update each other as our ends of relationships evolve and move.

Alongside this post, we are open-sourcing our Swift implementation of the protocol under the MIT license.

Architecture

The AC Protocol is primarily a protocol between people, performed by their user agent - an app acting on behalf of an individual user. The ends of the protocol are these user agents, with some lightweight assistance from servers at the transport layer for storing and forwarding ciphertexts it can’t decrypt.

An architecture diagram depicting messages exchanged between Alice on the left and Bob on the right. Between them, each has a phone depicting their user agent. Between the phones are cloud symbols representing servers, one near Alice and one near Bob. Both are green as Germ operates both servers. Messages travel from Alice’s phone, to the green server near Alice, to the green server near Bob, then to Bob’s phone - and vice versa. A dim yellow cloud near Bob represents a potential, non-Germ server, that Bob chooses to route his messages through.

Today, that user agent is the Germ app on your iPhone, with the help of Germ’s servers; we envision the Germ app available on any of your computing devices, acting cooperatively as a unified user agent. We also anticipate that you’ll want to talk to people who want to use a different user agent, or different servers, for themselves. Germ is designed for that interoperable future, where people’s autonomy over their choice of user agent doesn’t get in the way of their conversations.

AC Identity Layer

The core concept in the AC identity layer that allows for permission to contact is the separation of Identity as a user-facing representation, from that Identity’s participation in many conversations, for which it delegates Agent objects. AC Identities do not directly participate conversations - you can’t directly send messages to identities. Instead, they’re a basis for recognizing which agents share a user-facing representation. Agents can send and receive E2EE messages, and a new one is created for each conversation, so that you can leave a conversation by closing your agent in that conversation, without affecting other conversations where you’re presenting the same identity.

The Identity layer uses signing keys as the basis for these objects.

  • Identities represent a user-facing identity - a name, photo, and pronouns. In the Germ app, these are represented as cards.
    • Identity objects use their signing key to assert that its public key should be presented to users in this way.
      • By convention, the name, image, and image alt text should be considered immutable properties of an identity signing key, while other associated data such as pronouns may be mutable.
      • An identity key can issue multiple, ordered assertions for its mutable data, but to change its name, image, or image alt text it must designate a successor identity with the new name and image.
    • Identities also use their signing key to assert that within a particular conversation, they should be succeeded by another identity. (Both the predecessor and successor identities must sign this assertion for it to be accepted)
  • Agents
    • Agents must have a parent identity, and both agent and parent identity must bidirectionally sign this delegation of identity to the agent.
    • Agents participate in conversations by declaring (signing over) encryption keys and addresses for itself.
    • Conversations in Germ are backed by an MLS group whose members are agent objects in the identity layer.
    • Just as with identities, agents can also nominate successors.

The Germ app creates these AC Identity and Agent objects for you when you create and edit cards, and exchange them. These objects remain on your device, are never shared with Germ’s servers, and the private keys are stored so only you can access them. We envision a future where your AC Identity and Agent objects are shared among your computing devices for multi-device Germ usage.

In the Germ app, when people exchange Cards — which encapsulate an Identity and an Agent that is an invitation to connect — they form a Relationship. A relationship represents a connection between two people - Alice and Bob. At any point in time, the relationship’s ends are agents of Alice and Bob, which ensure that they can exchange E2EE messages. But these agents and identities are not fixed. As Alice and Bob change themselves or their software, they can evolve their representation in this relationship by telling the other in this E2EE channel. So just as I can change my name or address, and choose who to tell about these changes, the AT protocol reeimagines your contacts as living relationships that your user agent helps you to cultivate.

Interface with MLS

The AC Identity layer forms an Authentication Service for MLS. AC Agents map 1:1 to MLS clients, and the credential we use for MLS clients is a basic credential composed of the AC Agent’s public key. We ensure bidirectional binding between the AC Agent and MLS client by using the Agent to sign any MLS message that presents a new credential - a KeyPackage, Welcome, Proposal, or Commit.

MLS proposals to change a member’s credential are valid if and only if the Identity Layer has processed a valid agent (and if required, identity) succession, for the context of that MLS group.

Transport Layer

Once Bob’s agent Beta has produced an MLS private message in a MLS group composed of Beta and Alice’s agent Alpha, how does Bob transmit it to Alice?

We want Alice and Bob to have autonomy over their choices of software and services, so we don’t assume that both are members of the same messaging service. Instead, users tell each other where they can receive messages.

“You can send me messages to mailbox M at service S until time T”

Where S is a domain name, and M is an arbitrary string, assigned on request by the service. We call this (service, mailbox) pair an Address. Users exchange addresses when they change identities, and continue to issue new ones as they exchange messages. In the Germ app, these addresses are assigned exclusively to an AC agent, so that on receipt of a ciphertext at an address, the Germ app knows which MLS group it should try to decrypt the ciphertext for.

The private assignment among user agents of addresses to agents, keeps identity metadata out of the transport layer. All the server sees are ciphertexts destined for an address, and what device that address terminates at. It doesn’t need to know sender identity, nor can it determine which in-transit ciphertexts belong to the same conversation, unless addresses are reused for multiple messages.

Today, only Germ’s backend operates such a transport service, on behalf of Germ users. But we anticipate a future where Germ users will want to use our app and service to talk to friends who want to use different apps and services. This is an important dimension of user autonomy, and we’re designing a protocol for that interoperable future.

Moreover, this opens possibilities for diverse transport routing that we look forward to exploring, particularity in the ways that an app acting as the user’s agent can distill the complexity of network routing into interesting user features:

  • People could use multiple mailbox services concurrently to provide resiliency against service provider or network outages.
  • People could choose for themselves tradeoffs between latency and privacy in message delivery, as granularly as per-conversation.
  • People could coordinate these tradeoffs among each other - “This is my regular address, but in an emergency use this other one to ring me immediately.”

People today have already manage digital relationships in this way across multiple apps and identities, and we’re excited for the potential of this protocol to make these features more accessible and usable under a unified identity framework.

Rendezvous

Although addresses expire, people using the Germ app can reconnect by coordinating a rendezvous using shared secret values. For example, in an MLS group between Alice’s agent Alpha and Bob’s agent Beta, they can export a shared secret K from the group. They can then mix in the Alpha public key to derive a rendezvous address RA for Alpha (and similarly for Beta).

Alpha could then ask a service S to forward it messages for RA, allowing Beta to reconnect by sending messages addressed to RA at S. This forms a durable two-way channel - at the cost of some metadata leakage - as a fallback to frequently exchanged addresses.

Germ operates such a rendezvous service, on a different address space from addresses Germ assigns on request to users.

How it all fits together

Making introductions

In the Germ app, you create a representation of yourself as a card with a name and image. That card is backed by an AC identity and its signing key.

When Alice shares her card as an invitation to connect, the Germ app delegates a new agent from that card for this invitation. That agent signs an MLS keypackage message, an additional HPKE public key, and some transport addresses. This is packaged as a Hello message, encrypted with a symmetric key so that Germ cannot access the plaintext, and the ciphertext is uploaded to Germ’s servers. Alice shares her card by sharing the link to the ciphertext, along with the symmetric key.

If Alice shares her link and key with Bob by showing a QR code or sharing a link, Bob can retrieve the ciphertext and decrypt it to examine

  • Alice's shared Identity’s public key, which includes
    • the signed user-facing representation
    • the cross-signed delegation to the agent key
  • the invitation agent public key, which also signed
    • an MLS keypackage message,
    • an HPKE public key
    • addresses

With this data, Bob can form a group with a chosen identity of their own by

  • delegating a new agent for this relationship, with a corresponding MLS client
  • creating an MLS group
  • sending their identity data, agent data, and MLS welcome back to Alice, encrypted to the HPKE public key from her hello. We call this package a Reply.

On receipt of Bob’s reply, Alice can examine Bob’s identity, compare it to who she sent the Hello to, and choose to accept Bob’s reply by joining the MLS group he formed. Because Alice may have sent the Hello to multiple recipients, she'll immediately propose to change her membership in the group from the invitation agent contained in the Hello to a new agent she's created for this new relationship with Bob.

Reconnecting in an MLS session in Germ DM 2.1

In Germ 2.1, we shipped MLS as the message encryption layer, and decided to fully deprecate our previous encryption sessions. For users who previously exchanged cards in Germ, the Germ app can autonomously reestablish E2EE sessions over MLS using our identity and transport primitive, without any additional server assistance. We do so by re-running the card exchange protocol, now with MLS keypackages, using the identity and agent data users previously exchanged.

Let’s say Alice and Bob previously exchanged AC Identities and have a preexisting channel terminated by agents Alpha and Beta, respectively.

  • Upon upgrade to Germ 2.1.1,
    • Alice and Bob’s apps each independently determine who should initiate the reconnect for this connection. Suppose for this example that Alice should initiate.
    • Bob starts to listen for an MLS reconnect at a rendezvous address derived from both agent keys (by hashing). We mix in a static discriminator so that Alice and Bob agree this rendezvous is for MLS reconnect.
    • Alice’s app creates an abbreviated hello message for Alice’s agent Alpha to Bob’s agent Beta, omitting identity data that was previously exchanged. This abbreviated hello is just:
      • An MLS keypackage message whose credential is Alpha’s public key
      • An additional HPKE encapsulated key, and
      • Alpha’s signature over the previous two
    • This abbreviated hello contains Alpha’s public key, which we wish to keep private from Germ’s servers. So Alice uses HKDF to derive a symmetric key from Alpha’s public key, and uses that to encrypt the abbreviated hello.
    • Alice then periodically attempts to send their hello to the reconnect rendezvous address. Germ’s servers will report failure to Alice’s app until Bob upgrades to Germ 2.1.1 and registers to receive rendezvous messages at this address.
  • On receipt of the reconnect hello, Bob’s app can construct an MLS group with Alpha and Beta as members, returning to Alice the MLS welcome, additionally encrypted (to conceal the MLS message plaintext metadata) to the HPKE key in the abbreviated hello.
  • Just as in our initial key exchange, Bob can now send messages to Alice. On receipt of the MLS welcome, Alice can process Bob’s incoming messages and can also send messages to Bob.

Next

You can find further details in our open-source Swift implementation. We look forward to your feedback on this design.

This post has hinted at the ways we evolve identities in our MLS group, encrypt MLS messages to hide MLS metadata from our server (group id, epoch, and type of message), and package messages for resilient message exchange over unreliable transport channels. Our next post will describe these steps in more detail.

This protocol forms the basis for building communication tools that match and facilitate the ways we naturally form connections with each other. Today, we start from creating a connection between two people. We have lots more planned and we’re excited to share it with you.

Previous
Previous

Decentralized Pairwise MLS

Next
Next

Germ DM is now on Messaging Layer Security!