<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.6.34 (Ruby 3.2.2) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-ralston-mimi-linearized-matrix-01" category="std" consensus="true" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.17.2 -->
  <front>
    <title abbrev="Linearized Matrix API">Linearized Matrix API</title>
    <seriesInfo name="Internet-Draft" value="draft-ralston-mimi-linearized-matrix-01"/>
    <author fullname="Travis Ralston">
      <organization>The Matrix.org Foundation C.I.C.</organization>
      <address>
        <email>travisr@matrix.org</email>
      </address>
    </author>
    <author fullname="Matthew Hodgson">
      <organization>The Matrix.org Foundation C.I.C.</organization>
      <address>
        <email>matthew@matrix.org</email>
      </address>
    </author>
    <date year="2023" month="June" day="06"/>
    <area>Applications and Real-Time</area>
    <workgroup>More Instant Messaging Interoperability</workgroup>
    <keyword>matrix</keyword>
    <keyword>linearized</keyword>
    <keyword>interoperability</keyword>
    <keyword>messaging</keyword>
    <keyword>mimi</keyword>
    <abstract>
      <?line 57?>

<t>Matrix is an existing openly specified decentralized secure communications protocol
able to provide a framework for instant messaging interoperability. However, the
existing model can be complex to reason about for simple interoperability usecases.
With modifications to the room model, Matrix can support those simpler usecases more
easily.</t>
      <t>This document explores "Linearized Matrix": the modified room model still backed by
Matrix.</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        The latest revision of this draft can be found at <eref target="https://turt2live.github.io/ietf-mimi-linearized-matrix/draft-ralston-mimi-linearized-matrix.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-ralston-mimi-linearized-matrix/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        More Instant Messaging Interoperability Working Group mailing list (<eref target="mailto:mimi@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/mimi/"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/mimi/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/turt2live/ietf-mimi-linearized-matrix"/>.</t>
    </note>
  </front>
  <middle>
    <?line 68?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>Alongside messaging, Matrix operates as an openly federated communications protocol for
VoIP, IoT, and more. The existing Matrix network uses fully decentralized access control
within rooms (conversations) and is highly extensible in its structure. These features
are not critically important to a strict focus on messaging interoperability, however.</t>
      <t>This document describes "Linearized Matrix": a modified room model based upon Matrix's
existing room model. This document does <em>not</em> explore how to interconnect Linearized
Matrix with the existing Matrix room model - interested readers may wish to review
MSC3995 <xref target="MSC3995"/> within the Matrix Specification process.</t>
    </section>
    <section anchor="conventions-and-definitions">
      <name>Conventions and Definitions</name>
      <t>This document uses <xref target="I-D.ralston-mimi-terminology"/> where possible.</t>
      <t>This document additionally uses the following definitions:</t>
      <ul spacing="normal">
        <li>
          <strong>Room</strong>: Synonymous with "conversation" from I-D.ralston-mimi-terminology.</li>
        <li>
          <strong>Room Member</strong>: Synonymous with "conversation member" from I-D.ralston-mimi-terminology.</li>
        <li>
          <strong>State Event</strong>: Synonymous with "conversation property" from I-D.ralston-mimi-terminology.
A state event is a subclass of an event.</li>
      </ul>
      <t>Further terms are introduced in-context within this document.</t>
      <t><strong>TODO</strong>: We should move/copy those definitions up here anyways.</t>
    </section>
    <section anchor="architecture">
      <name>Architecture</name>
      <t>For a given conversation/room:</t>
      <artset>
        <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="416" width="552" viewBox="0 0 552 416" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px">
            <path d="M 8,128 L 8,192" fill="none" stroke="black"/>
            <path d="M 40,72 L 40,128" fill="none" stroke="black"/>
            <path d="M 56,192 L 56,272" fill="none" stroke="black"/>
            <path d="M 104,200 L 104,240" fill="none" stroke="black"/>
            <path d="M 128,64 L 128,120" fill="none" stroke="black"/>
            <path d="M 160,128 L 160,192" fill="none" stroke="black"/>
            <path d="M 392,128 L 392,192" fill="none" stroke="black"/>
            <path d="M 392,224 L 392,288" fill="none" stroke="black"/>
            <path d="M 424,72 L 424,128" fill="none" stroke="black"/>
            <path d="M 424,296 L 424,352" fill="none" stroke="black"/>
            <path d="M 512,64 L 512,120" fill="none" stroke="black"/>
            <path d="M 512,288 L 512,344" fill="none" stroke="black"/>
            <path d="M 544,128 L 544,192" fill="none" stroke="black"/>
            <path d="M 544,224 L 544,288" fill="none" stroke="black"/>
            <path d="M 40,32 L 128,32" fill="none" stroke="black"/>
            <path d="M 424,32 L 512,32" fill="none" stroke="black"/>
            <path d="M 40,64 L 128,64" fill="none" stroke="black"/>
            <path d="M 424,64 L 512,64" fill="none" stroke="black"/>
            <path d="M 8,128 L 160,128" fill="none" stroke="black"/>
            <path d="M 392,128 L 544,128" fill="none" stroke="black"/>
            <path d="M 160,144 L 248,144" fill="none" stroke="black"/>
            <path d="M 320,144 L 384,144" fill="none" stroke="black"/>
            <path d="M 168,176 L 248,176" fill="none" stroke="black"/>
            <path d="M 320,176 L 392,176" fill="none" stroke="black"/>
            <path d="M 8,192 L 160,192" fill="none" stroke="black"/>
            <path d="M 392,192 L 544,192" fill="none" stroke="black"/>
            <path d="M 392,224 L 544,224" fill="none" stroke="black"/>
            <path d="M 104,240 L 248,240" fill="none" stroke="black"/>
            <path d="M 320,240 L 392,240" fill="none" stroke="black"/>
            <path d="M 56,272 L 248,272" fill="none" stroke="black"/>
            <path d="M 320,272 L 384,272" fill="none" stroke="black"/>
            <path d="M 392,288 L 544,288" fill="none" stroke="black"/>
            <path d="M 424,352 L 512,352" fill="none" stroke="black"/>
            <path d="M 424,384 L 512,384" fill="none" stroke="black"/>
            <path d="M 40,32 C 31.16936,32 24,39.16936 24,48" fill="none" stroke="black"/>
            <path d="M 128,32 C 136.83064,32 144,39.16936 144,48" fill="none" stroke="black"/>
            <path d="M 424,32 C 415.16936,32 408,39.16936 408,48" fill="none" stroke="black"/>
            <path d="M 512,32 C 520.83064,32 528,39.16936 528,48" fill="none" stroke="black"/>
            <path d="M 40,64 C 31.16936,64 24,56.83064 24,48" fill="none" stroke="black"/>
            <path d="M 128,64 C 136.83064,64 144,56.83064 144,48" fill="none" stroke="black"/>
            <path d="M 424,64 C 415.16936,64 408,56.83064 408,48" fill="none" stroke="black"/>
            <path d="M 512,64 C 520.83064,64 528,56.83064 528,48" fill="none" stroke="black"/>
            <path d="M 424,352 C 415.16936,352 408,359.16936 408,368" fill="none" stroke="black"/>
            <path d="M 512,352 C 520.83064,352 528,359.16936 528,368" fill="none" stroke="black"/>
            <path d="M 424,384 C 415.16936,384 408,376.83064 408,368" fill="none" stroke="black"/>
            <path d="M 512,384 C 520.83064,384 528,376.83064 528,368" fill="none" stroke="black"/>
            <polygon class="arrowhead" points="520,344 508,338.4 508,349.6" fill="black" transform="rotate(90,512,344)"/>
            <polygon class="arrowhead" points="520,120 508,114.4 508,125.6" fill="black" transform="rotate(90,512,120)"/>
            <polygon class="arrowhead" points="432,296 420,290.4 420,301.6" fill="black" transform="rotate(270,424,296)"/>
            <polygon class="arrowhead" points="432,72 420,66.4 420,77.6" fill="black" transform="rotate(270,424,72)"/>
            <polygon class="arrowhead" points="392,272 380,266.4 380,277.6" fill="black" transform="rotate(0,384,272)"/>
            <polygon class="arrowhead" points="392,144 380,138.4 380,149.6" fill="black" transform="rotate(0,384,144)"/>
            <polygon class="arrowhead" points="176,176 164,170.4 164,181.6" fill="black" transform="rotate(180,168,176)"/>
            <polygon class="arrowhead" points="136,120 124,114.4 124,125.6" fill="black" transform="rotate(90,128,120)"/>
            <polygon class="arrowhead" points="112,200 100,194.4 100,205.6" fill="black" transform="rotate(270,104,200)"/>
            <polygon class="arrowhead" points="48,72 36,66.4 36,77.6" fill="black" transform="rotate(270,40,72)"/>
            <g class="text">
              <text x="76" y="52">Client</text>
              <text x="112" y="52">A</text>
              <text x="460" y="52">Client</text>
              <text x="496" y="52">B</text>
              <text x="200" y="100">Client-Server</text>
              <text x="272" y="100">API</text>
              <text x="284" y="148">events</text>
              <text x="80" y="164">Provider/Server</text>
              <text x="464" y="164">Provider/Server</text>
              <text x="80" y="180">A</text>
              <text x="284" y="180">events</text>
              <text x="464" y="180">B</text>
              <text x="256" y="196">Server-Server</text>
              <text x="328" y="196">API</text>
              <text x="284" y="244">events</text>
              <text x="464" y="260">Provider/Server</text>
              <text x="284" y="276">events</text>
              <text x="464" y="276">C</text>
              <text x="460" y="372">Client</text>
              <text x="496" y="372">C</text>
            </g>
          </svg>
        </artwork>
        <artwork type="ascii-art"><![CDATA[
       .------------.                                  .------------.
      |   Client A   |                                |   Client B   |
       '-----------+'                                  '-----------+'
        ^          |                                    ^          |
        |          |  Client-Server API                 |          |
        |          V                                    |          V
    +---+--------------+                            +---+--------------+
    |                  +----------( events )------->|                  |
    | Provider/Server  |                            | Provider/Server  |
    |        A         |<---------( events )--------+        B         |
    +-----+------------+     Server-Server API      +------------------+
          |     ^
          |     |                                   +------------------+
          |     +-----------------( events )--------+                  |
          |                                         | Provider/Server  |
          +-----------------------( events )------->|        C         |
                                                    +--------------+---+
                                                        ^          |
                                                        |          |
                                                        |          V
                                                       .+-----------.
                                                      |   Client C   |
                                                       '------------'
]]></artwork>
      </artset>
      <t>In this diagram, Server A is acting as a hub for the other two servers. Servers B and C do
not converse directly when sending events to the room: those events are instead sent to the
hub which then distributes them back out to all participating servers.</t>
      <t>Clients are shown in the diagram here for demonstrative purposes only. No client-server API
is specified as part of Linearized Matrix, and the clients can be pre-existing or newly
created for messaging. The objects given to clients are implementation-dependent, though
for simplicity may be events.</t>
      <t>This leads to two distinct roles:</t>
      <ul spacing="normal">
        <li>
          <strong>Hub server</strong>: the server responsible for holding conversation history on behalf of
other servers in the room.</li>
        <li>
          <strong>Participant server</strong>: any non-hub server. This server is not required to persist
conversation history as it can fetch it from the hub if needed.</li>
      </ul>
      <t><strong>OPEN QUESTION</strong>: Should we support having multiple hubs for increased trust between
participant and hub? (participant can pick the hub it wants to use rather than being
forced to use a single hub)</t>
      <section anchor="server-names-domain-names">
        <name>Server names / domain names</name>
        <t>Throughout this document servers are referred to as having a "domain name" or "server name".
A server name MUST be compliant with RFC 1123 (Section 2.1) <xref target="RFC1123"/>.</t>
        <t><strong>TODO</strong>: Should we incorporate Matrix's IPv6 extension, or are we able to assume that
everyone will be using non-literal hostnames?</t>
        <t><strong>TODO</strong>: Do we really need to make this case sensitive? Matrix does, but is that correct?</t>
      </section>
      <section anchor="rooms">
        <name>Rooms</name>
        <t>A room is a conceptual place where users send and receive events. Events are sent to a room,
and all users which have sufficient access will receive that event.</t>
        <t>Rooms have a single internal "Room ID" to identify them from another room:</t>
        <artwork><![CDATA[
!<opaque>:<domain>
]]></artwork>
        <t>For example, <tt>!abc:example.org</tt>.</t>
        <t>The opaque portion of the room ID, called the localpart, must not be empty and must consist
entirely of the characters <tt>[0-9a-zA-Z._~-]</tt>.</t>
        <t>The domain portion of a room ID does <em>NOT</em> indicate the room is "hosted" or served by that
domain. The domain is used as a namespace to prevent another server from maliciously taking
over a room. The server represented by that domain may no longer be participating in the room.</t>
        <t>The total length (including the sigil and domain) of a room ID MUST NOT exceed 255 characters.</t>
        <t>Room IDs are case sensitive.</t>
      </section>
      <section anchor="users">
        <name>Users</name>
        <t>As described by <xref target="I-D.ralston-mimi-terminology"/>, a user is typically a human which operates
a client. In Linearized Matrix, all users have a User ID to distinguish them:</t>
        <artwork><![CDATA[
@<localpart>:<domain>
]]></artwork>
        <t>The localpart portion of the user ID is expected to be human-readable, MUST NOT be empty,
and MUST consist solely of <tt>[0-9a-z._=-/]</tt> characters. Note that user IDs <em>cannot</em> contain
uppercase letters in the localpart.</t>
        <t>The domain portion indicates which server allocated the ID, or would allocate the resource
if the user doesn't exist yet. <tt>@alice:first.example.org</tt> is a different user on a different
server from <tt>@alice:second.example.org</tt>, for example.</t>
        <t>The total length (including the sigil and domain) of a user ID MUST NOT exceed 255 characters.</t>
        <t>User IDs are case sensitive.</t>
        <t><strong>Note</strong>: User IDs are sometimes informally referenced as "MXIDs", short for "Matrix User IDs".</t>
        <t><strong>Author's note</strong>: This draft assumes that an external system will resolve phone number to
user ID, somehow. Or that <tt>@18005552222:example.org</tt> will resolve to <tt>+1 800 555 2222</tt> on
a given server, or similar.</t>
      </section>
      <section anchor="devices">
        <name>Devices</name>
        <t>Each user can have zero or more devices/active clients. These devices are intended to be members
of the MLS group and thus have their own key package material associated with them.</t>
        <t><strong>TODO</strong>: Do we need to define grammar and such for device IDs, or is that covered by MLS already?</t>
      </section>
      <section anchor="events">
        <name>Events</name>
        <t>All data exchanged over Linearized Matrix is expressed as an "event". Each client action
(such as sending a message) correlates with exactly one event. All events have a <tt>type</tt>
to distinguish them, and use reverse domain name notation to namespace custom events
(for example, <tt>org.example.appname.eventname</tt>). Event types specified by Linearized Matrix
itself use <tt>m.</tt> as their namespace.</t>
        <t>When events are traversing a transport to another server they are often referred to as a
<strong>Persistent Data Unit</strong> or <strong>PDU</strong>.</t>
        <t>An event has many other fields:</t>
        <ul spacing="normal">
          <li>
            <tt>room_id</tt> (string; required) - The room ID for where the event is being sent.</li>
          <li>
            <tt>type</tt> (string; required) - A UTF-8 <xref target="RFC3629"/> string to distinguish different data types
being carried by events. All event types use a reverse domain name notation to namespace
themselves (for example, <tt>org.example.appname.eventname</tt>). Event types specified by
Linearized Matrix itself use <tt>m</tt> as their namespace (for example, <tt>m.room.member</tt>).</li>
          <li>
            <tt>state_key</tt> (string; optional) - A UTF-8 <xref target="RFC3629"/> string to further distinguish an event
type from other related events. Only specified on State Events (discussed later). Can be
empty.</li>
          <li>
            <tt>sender</tt> (string; required) - The user ID which is sending this event.</li>
          <li>
            <tt>origin_server_ts</tt> (integer; required) - The milliseconds since the unix epoch for when this
event was created.</li>
          <li>
            <tt>hub_server</tt> (string; technically optional) - The domain name of the hub server which is
sending this event to the remainder of the room. Note that all events created within Linearized
Matrix will have this field set.</li>
          <li>
            <tt>content</tt> (object; required) - The event content. The schema of this is specific to the event
type, and should be considered untrusted data until verified otherwise. Malicious servers and
clients can, for example, exclude important fields, use invalid value types, or otherwise
attempt to disrupt a client - receivers should treat the event with care while processing.</li>
          <li>
            <tt>hashes</tt> (object; required) - Keyed by hash algorithm, the <em>content hash</em> for the event.</li>
          <li>
            <tt>signatures</tt> (object; required) - Keyed first by domain name then by key ID, the signatures for
the event.</li>
          <li>
            <tt>auth_events</tt> (array of strings; required) - The event IDs which prove the sender is able to
send this event in the room. Which specific events are put here are defined by the <em>auth events
selection</em> algorithm.</li>
          <li>
            <tt>prev_events</tt> (array of strings; required) - The event IDs which precede the event. Note that all
events generated within Linearized Matrix will only ever have a single event ID here.</li>
          <li>
            <tt>unsigned</tt> (object; optional) - Additional metadata not covered by the signing algorithm.</li>
        </ul>
        <t>Note that an event ID is not specified on the schema. Event IDs are calculated to ensure accuracy
and consistency between servers. To calculate an event ID, calculate the <em>reference hash</em> of the
event, encode it using <em>URL-safe Unpadded Base64</em>, and prefix it with the event ID sigil, <tt>$</tt>.</t>
        <t>If both the sender and receiver are implementing the algorithms correctly, the event ID will be
the same. When different, the receiver will have issues accepting the event (none of the <tt>auth_events</tt>
will make sense, for example). Both sender and receiver should review their algorithm implementation
to verify everything is according to the specification in this case.</t>
        <t>Events are treated as JSON <xref target="RFC8259"/> within the protocol, but can be encoded and represented by
any binary-compatible format. Additional overhead may be introduced when converting between formats,
however.</t>
        <t>An example may be:</t>
        <sourcecode type="json"><![CDATA[
{
  "room_id": "!abc:example.org",
  "type": "m.room.member",
  "state_key": "@alice:first.example.org",
  "sender": "@bob:second.example.org",
  "origin_server_ts": 1681340188825,
  "hub_server": "first.example.org",
  "content": {
    "membership": "invite"
  },
  "hashes": {
    "sha256": "<unpadded base64>"
  },
  "signatures": {
    "first.example.org": {
      "ed25519:1": "<unpadded base64 for signature covering whole event>"
    },
    "second.example.org": {
      "ed25519:1": "<unpadded base64 for signature covering LPDU>"
    }
  },
  "auth_events": ["$first", "$second"],
  "prev_events": ["$parent"],
  "unsigned": {
    "arbitrary": "fields"
  }
}
]]></sourcecode>
        <section anchor="linearized-pdu">
          <name>Linearized PDU</name>
          <t>The hub server is responsible for ensuring events are linearly added to the room from all participants,
which means participants cannot set fields such as <tt>prev_events</tt> on their events. Additionally,
participant servers are not expected to store past conversation history or even "current state" for
the room, further making participants unable to reliably populate <tt>auth_events</tt> and <tt>prev_events</tt>.</t>
          <t>To avoid these problems, the participant server <em>does not</em> populate the following fields on events
they are sending to the hub:</t>
          <ul spacing="normal">
            <li>
              <tt>auth_events</tt> - the participant cannot reliably determine what allows it to send the event.</li>
            <li>
              <tt>prev_events</tt> - the participant cannot reliably know what event precedes theirs.</li>
            <li>
              <tt>hashes</tt> - the hashes cover the above two fields.</li>
          </ul>
          <t>The participant server will receive an echo of the fully-formed event from the hub once appended.
To ensure authenticity, the participant server signs this "Linearized PDU" or "LPDU" using the
normal event <em>signing algorithm</em>.</t>
          <t><strong>TODO</strong>: While a signature is great, it doesn't cover the content. We need to fix <tt>hashes</tt> to
actually support an LPDU hash alongside a full-blown content hash.</t>
        </section>
        <section anchor="state-events">
          <name>State events</name>
          <t>State events track metadata for the room, such as name, topic, and members. State is keyed by a
tuple of <tt>type</tt> and <tt>state_key</tt>, noting that an empty string is a valid state key. State in the
room with the same key-tuple will be overwritten.</t>
          <t>State events are otherwise processed like regular events in the room: they're appended to the
room history and can be referenced by that room history.</t>
          <t>"Current state" is the state at the time being considered (which is often the implied <tt>HEAD</tt> of
the room). In Linearized Matrix, a simple approach to calculating current state is to iterate
over all events in order, overwriting the key-tuple for state events in an adjacent map. That
map becomes "current state" when the loop is finished.</t>
        </section>
        <section anchor="event-types">
          <name>Event types</name>
          <t>Linearized Matrix defines the following event types:</t>
          <section anchor="mroomcreate">
            <name><tt>m.room.create</tt></name>
            <t>The very first event in the room. It MUST NOT have any <tt>auth_events</tt> or <tt>prev_events</tt>, and the
domain of the <tt>sender</tt> MUST be the same as the domain in the <tt>room_id</tt>. The <tt>state_key</tt> MUST
be an empty string.</t>
            <t>The <tt>content</tt> for a create event MUST have at least a <tt>room_version</tt> field to denote what set
of algorithms the room is using. This document as a whole describes a single room version
identified as <tt>I.1</tt>.</t>
            <t><strong>Implementation note</strong>: Currently <tt>I.1</tt> is not a real thing. Use
<tt>org.matrix.i-d.ralston-mimi-linearized-matrix.00</tt> when testing against other Linearized Matrix
implementations. This room version may be updated later.</t>
            <t><strong>TODO</strong>: Describe room versions more?</t>
          </section>
          <section anchor="mroomjoinrules">
            <name><tt>m.room.join_rules</tt></name>
            <t>Defines whether users can join without an invite and other similar conditions. The <tt>state_key</tt>
MUST be an empty string.</t>
            <t>The <tt>content</tt> for a join rules event MUST have at least a <tt>join_rule</tt> field to denote the
join policy for the room. Allowable values are:</t>
            <ul spacing="normal">
              <li>
                <tt>public</tt> - anyone can join without an invite.</li>
              <li>
                <tt>knock</tt> - users must receive an invite to join, and can request an invite (knock) too.</li>
              <li>
                <tt>invite</tt> - users must receive an invite to join.</li>
            </ul>
            <t><strong>TODO</strong>: Describe <tt>restricted</tt> (and <tt>knock_restricted</tt>) rooms?</t>
          </section>
          <section anchor="mroommember">
            <name><tt>m.room.member</tt></name>
            <t>Defines the membership for a user in the room. If the user does not have a membership event then
they are presumed to be in the <tt>leave</tt> state.</t>
            <t>The <tt>state_key</tt> MUST be a non-empty string denotating the user ID the membership is affecting.</t>
            <t>The <tt>content</tt> for a membership event MUST have at least a <tt>membership</tt> field to denote the
membership state for the user. Allowable values are:</t>
            <ul spacing="normal">
              <li>
                <tt>leave</tt> - not participating in the room. If the <tt>state_key</tt> and <tt>sender</tt> do not match, this was
a kick rather than voluntary leave.</li>
              <li>
                <tt>join</tt> - participating in the room.</li>
              <li>
                <tt>knock</tt> - requesting an invite to the room.</li>
              <li>
                <tt>invite</tt> - invited to participate in the room.</li>
              <li>
                <tt>ban</tt> - implies kicked/not participating. Cannot be invited or join the room without being
unbanned first (moderator sends a kick, essentially).</li>
            </ul>
            <t>The <em>auth rules</em> define how these membership states interact and what legal transitions are possible.
For example, preventing users from unbanning themselves falls under the auth rules.</t>
          </section>
          <section anchor="mroompowerlevels">
            <name><tt>m.room.power_levels</tt></name>
            <t>Defines what given users can and can't do, as well as which event types they are able to send.
The enforcement of these power levels is determined by the <em>auth rules</em>.</t>
            <t>The <tt>state_key</tt> MUST be an empty string.</t>
            <t>The <tt>content</tt> for a power levels event SHOULD have at least the following:</t>
            <ul spacing="normal">
              <li>
                <tt>ban</tt> (integer) - the level required to ban a user. Defaults to <tt>50</tt> if unspecified.</li>
              <li>
                <tt>kick</tt> (integer) - the level required to kick a user. Defaults to <tt>50</tt> if unspecified.</li>
              <li>
                <tt>invite</tt> (integer) - the level required to invite a user. Defaults to <tt>0</tt> if unspecified.</li>
              <li>
                <tt>redact</tt> (integer) - the level required to redact an event sent by another user. Defaults
to <tt>50</tt> if unspecified.</li>
              <li>
                <tt>events</tt> (map) - keyed by event type string, the level required to send that event type to
the room. Defaults to an empty map if unspecified.</li>
              <li>
                <tt>events_default</tt> (integer) - the level required to send events in the room. Overridden by
the <tt>events</tt> map. Defaults to <tt>0</tt> if unspecified.</li>
              <li>
                <tt>state_default</tt> (integer) - the level required to send state events in the room. Overridden
by the <tt>events</tt> map. Defaults to <tt>50</tt> if unspecified.</li>
              <li>
                <tt>users</tt> (map) - keyed by user ID, the level of that user. Defaults to an empty map if
unspecified.</li>
              <li>
                <tt>users_default</tt> (integer) - the level for users. Overridden by the <tt>users</tt> map. Defaults to
<tt>0</tt> if unspecified.</li>
            </ul>
            <t><strong>TODO</strong>: Include notifications for at-room here too?</t>
            <t>Note that if no power levels event is specified in the room then the room creator (<tt>sender</tt> of
the <tt>m.room.create</tt> state event) has a default power level of 100.</t>
          </section>
          <section anchor="todo-other-events">
            <name>TODO: Other events</name>
            <t><strong>TODO</strong>: <tt>m.room.name</tt>, <tt>m.room.topic</tt>, <tt>m.room.avatar</tt>, <tt>m.room.encryption</tt>, <tt>m.room.history_visibility</tt></t>
            <t><strong>TODO</strong>: Drop <tt>m.room.encryption</tt> and pack it into the create event instead?</t>
          </section>
        </section>
      </section>
    </section>
    <section anchor="mls-considerations">
      <name>MLS Considerations</name>
      <t>MIMI has a chartered requirement to use MLS for encryption, and MLS requires that all group
members (devices) know of all other devices. If we consider each Matrix room to have an MLS
group, we encounter scenarios where the room and group membership might diverge or otherwise
not be equivalent.</t>
      <t>In a traditional Matrix room, membership is not managed at a per-device level but rather a
per-user level. Devices are authenticated to use the room by being attached to a user. This
model doesn't work in MLS, though.</t>
      <t>A couple of options present themselves:</t>
      <ol spacing="normal" type="1"><li>Keep managing the room state at the server level, as is traditional for Matrix, and define
a set of rules/methods for engaging devices/users in the room with the MLS group. Servers
have an ability to instruct devices on how/when to add/remove MLS group members, but not
an ability to handle the MLS Proposals and Commits directly.</li>
        <li>Coordinate a room's state at the device level, leaving servers to figure out how to push
events between servers (and by extension, other devices). Servers would not have knowledge
or ability to reject proposals based on authorization beyond transport-level authenticity
concerns.</li>
      </ol>
      <t>At this stage of drafting in the document, it is not clear which would be preferred. Both are
explored.</t>
      <section anchor="server-side-room-model">
        <name>Server-side Room Model</name>
        <t>In this model, servers handle the room state on behalf of devices. This gives the server an
ability to apply access control at a user level, and instruct other devices on when/how to
add or remove devices from the underlying MLS group. The server does not have an ability to
participate in the MLS group directly.</t>
        <t>This is how traditional Matrix rooms work by handling state changes (user membership, etc)
in cleartext for everyone to see. A user's devices would be tracked and added/removed from
the MLS group as needed.</t>
        <t>The exact rules for how a user's devices become engaged with the MLS group is not yet defined.</t>
        <t>An advantage over this model compared to client-side is the server is able to reduce the
client's traffic by rejecting events earlier and deal with conflicts that may arise, keeping
the conversation as linear as possible for the client.</t>
        <t>A clear disadvantage is that without cross-signing or other cryptographic mechanism, the server
would be able to add malicious devices to its users and therefore the MLS group. A precise
mitigation strategy is not yet defined by this document, but would involve building verifiable
trust in a device before it is allowed to participate in the MLS group.</t>
        <t>The existing model used by Linearized Matrix is covered by "Event Signing &amp; Authorization"
later in this document.</t>
        <t><strong>TODO</strong>: We might also need DMLS to handle some of the server-side conflicts?</t>
      </section>
      <section anchor="client-side-room-model">
        <name>Client-side Room Model</name>
        <t>Here, the room's state is completely managed within the MLS group. This provides a key advantage
where servers become message-passing nodes (in essence), but increases implementation complexity
on the clients/devices.</t>
        <t>Much of this model is based around the server-side model discussed above: event authorization rules,
redactions, etc still behave the same, but on the client-side instead. The server would likely be
responsible for ensuring incoming events are properly signed, but otherwise leave it up to clients to
accept or reject them into their internal linked list.</t>
        <t>A potential consequence of this model is clients needing to implement a conflict resolution algorithm
despite having linear room history. This is due to clients receiving MLS messages out of guaranteed order.</t>
        <t><strong>TODO</strong>: This could be DMLS, state res, or both.</t>
      </section>
    </section>
    <section anchor="event-signing-authorization">
      <name>Event Signing &amp; Authorization</name>
      <t>There are a few aspects of an event which verify its authenticity and therefore whether it
can be accepted into the room. All of these checks work with the fully-formed PDU for an
event.</t>
      <t>First, the event has a <em>content hash</em> which covers the unredacted content of the event. The
purpose of this hash is to ensure that the original contents are not modified, therefore if
the hash check fails then the event is redacted before continuing processing. This removes
any potentially malicious or malformed details from the event.</t>
      <t>Second, the event has a <em>reference hash</em> which covers the redacted event. This hash serves
as the event's ID and thus any difference in calculation will result in an entirely different
event ID.</t>
      <t>Third, the event must be signed by the domain implied by the <tt>sender</tt>. In Linearized Matrix,
this will usually be the LPDU signature discussed earlier in this document. This signature
covers the content hash of the event.</t>
      <t><strong>TODO</strong>: Except the LPDU signature doesn't cover the participant's content hash, because
the participant doesn't have a content hash at the moment.</t>
      <t>Finally, the event must be signed by the <tt>hub_server</tt> domain if present. This is to ensure
that the event has actually been processed by the hub and isn't falsely being advertised as
sent by a hub.</t>
      <t><strong>TODO</strong>: Does the hub's signature actually guard anything?</t>
      <section anchor="checks-performed-upon-receipt-of-a-pduevent">
        <name>Checks performed upon receipt of a PDU/event</name>
        <t>When a hub receives an LPDU from a participant it adds the missing fields to create a fully
formed PDU then sends that PDU back out to all participants, including the original sender.</t>
        <t>When a server (hub or participant) receives a PDU, it:</t>
        <ol spacing="normal" type="1"><li>Verifies the event is in a valid shape. This will mean ensuring the required schema is
met and of the correct type (there is a string <tt>type</tt>, etc). Note that the event may
have additional fields in various places, such as at the top level or within <tt>content</tt>:
the receiver should ensure these additional fields do not cause the event to be invalid.
If the event fails this validation, it is dropped.</li>
          <li>Ensures the required signatures are present and valid. If the event fails this, it is
dropped.</li>
          <li>Ensures the event has a valid content hash. If the event's hash doesn't match, it is
redacted before processing further. The server will ultimately persist the redacted
copy.</li>
          <li>Ensures the event passes the authorization rules for the state identified by the event's
<tt>auth_events</tt>. If it fails, it is rejected.</li>
          <li>Ensures the event passes the authorization rules for the state of the room immediately
before where the event would be inserted. If it fails, it is rejected.</li>
          <li>Ensures the event passes the authorization rules for the current state of the room (which
may very well be the same as the step above). If it fails, it is soft-failed.</li>
        </ol>
      </section>
      <section anchor="rejection">
        <name>Rejection</name>
        <t>Events which are rejected are not relayed to any local clients and are not appended to the
room in any way. Within Linearized Matrix, events which reference rejected events are
rejected themselves.</t>
      </section>
      <section anchor="soft-failure">
        <name>Soft failure</name>
        <t>When an event is "soft-failed" it should not be relayed to any local clients nor be used
in <tt>auth_events</tt>. The event is otherwise handled as per usual.</t>
      </section>
      <section anchor="authorization-rules">
        <name>Authorization rules</name>
        <t>These are the rules which govern whether an event is accepted into the room, depending on
the state events surrounding that event. A given event is checked against multiple different
sets of state.</t>
        <section anchor="auth-events-selection">
          <name>Auth events selection</name>
          <t>The <tt>auth_events</tt> on an event MUST consist of the following state events, with the exception
of an <tt>m.room.create</tt> event which has no <tt>auth_events</tt>.</t>
          <ol spacing="normal" type="1"><li>The <tt>m.room.create</tt> state event.</li>
            <li>The current <tt>m.room.power_levels</tt> state event, if any.</li>
            <li>The sender's current <tt>m.room.member</tt> state event, if any.</li>
            <li>
              <t>If the <tt>type</tt> is <tt>m.room.member</tt>:
              </t>
              <ol spacing="normal" type="1"><li>The target's (<tt>state_key</tt>) current <tt>m.room.member</tt> state event, if any.</li>
                <li>If <tt>content.membership</tt> is <tt>join</tt> or <tt>invite</tt>, the current <tt>m.room.join_rules</tt> state
event, if any.</li>
              </ol>
            </li>
          </ol>
          <t><strong>TODO</strong>: Talk about restricted room joins here?</t>
        </section>
        <section anchor="auth-rules-algorithm">
          <name>Auth rules algorithm</name>
          <t>With consideration for default/calculated power levels, the ordered rules which affect
authorization of a given event are:</t>
          <t><strong>TODO</strong>: should we reference <tt>m.federate</tt>?</t>
          <ol spacing="normal" type="1"><li>Events must be signed by the server denoted by the <tt>sender</tt> field. Note that this may be
an LPDU if the <tt>hub_server</tt> is specified and not the same server.</li>
            <li>If <tt>hub_server</tt> is present, events must be signed by that server.</li>
            <li>
              <t>If <tt>type</tt> is <tt>m.room.create</tt>:  </t>
              <ol spacing="normal" type="1"><li>If it has any <tt>prev_events</tt>, reject.</li>
                <li>If the domain of the <tt>room_id</tt> is not the same domain as the <tt>sender</tt>, reject.</li>
                <li>If <tt>content.room_version</tt> is not <tt>I.1</tt>, reject. <strong>TODO</strong>: Incorporate room versions properly.</li>
                <li>Otherwise, allow.</li>
              </ol>
            </li>
            <li>
              <t>Considering the event's <tt>auth_events</tt>:  </t>
              <ol spacing="normal" type="1"><li>If there are duplicate entries for a given <tt>type</tt> and <tt>state_key</tt> pair, reject.</li>
                <li>If there are entries whose <tt>type</tt> and <tt>state_key</tt> do not match those specified by the
auth events selection algorithm, reject.</li>
                <li>If there are entries where the referenced event was rejected during receipt, reject.</li>
                <li>If there is no <tt>m.room.create</tt> event among the entries, reject.</li>
              </ol>
            </li>
            <li>
              <t>If <tt>type</tt> is <tt>m.room.member</tt>:  </t>
              <ol spacing="normal" type="1"><li>If there is no <tt>state_key</tt> property, or no <tt>membership</tt> in <tt>content</tt>, reject.</li>
                <li>
                  <t>If <tt>membership</tt> is <tt>join</tt>:      </t>
                  <ol spacing="normal" type="1"><li>If the previous event is an <tt>m.room.create</tt> event and the <tt>state_key</tt> is the
creator, allow.</li>
                    <li>If <tt>sender</tt> does not match <tt>state_key</tt>, reject.</li>
                    <li>If the <tt>sender</tt> is banned, reject.</li>
                    <li>If the <tt>join_rule</tt> for <tt>m.room.join_rules</tt> is <tt>invite</tt> or <tt>knock</tt>, then allow if
the current membership state is <tt>invite</tt> or <tt>join</tt>.</li>
                    <li>If the <tt>join_rule</tt> for <tt>m.room.join_rules</tt> is <tt>public</tt>, allow.</li>
                    <li>Otherwise, reject.</li>
                  </ol>
                </li>
                <li>
                  <t>If <tt>membership</tt> is <tt>invite</tt>:      </t>
                  <ol spacing="normal" type="1"><li>If the <tt>sender</tt>'s current membership state is not <tt>join</tt>, reject.</li>
                    <li>If the target user's (<tt>state_key</tt>) membership is <tt>join</tt> or <tt>ban</tt>, reject.</li>
                    <li>If the <tt>sender</tt>'s power level is greater than or equal to the power level needed
to send invites, allow.</li>
                    <li>Otherwise, reject.</li>
                  </ol>
                </li>
                <li>
                  <t>If <tt>membership</tt> is <tt>leave</tt>:      </t>
                  <ol spacing="normal" type="1"><li>If the <tt>sender</tt> matches the <tt>state_key</tt>, allow if and only if that user's current
membership state is <tt>knock</tt>, <tt>join</tt>, or <tt>invite</tt>.</li>
                    <li>If the <tt>sender</tt>'s current membership state is not <tt>join</tt>, reject.</li>
                    <li>If the target user's (<tt>state_key</tt>) current membership state is <tt>ban</tt>, and the
<tt>sender</tt>'s power level is less than the power level needed to ban other users, reject.</li>
                    <li>If the <tt>sender</tt>'s power level is greater than or equal to the power level needed to
kick users, and the target user's (<tt>state_key</tt>) power level is less than the <tt>sender</tt>'s,
allow.</li>
                    <li>Otherwise, reject.</li>
                  </ol>
                </li>
                <li>
                  <t>If <tt>membership</tt> is <tt>ban</tt>:      </t>
                  <ol spacing="normal" type="1"><li>If the <tt>sender</tt>'s current membership state is not <tt>join</tt>, reject.</li>
                    <li>If the <tt>sender</tt>'s power level is greater than or equal to the power level needed
to ban users, and the target user's (<tt>state_key</tt>) power level is less than the
<tt>sender</tt>'s power level, allow.</li>
                    <li>Otherwise, reject.</li>
                  </ol>
                </li>
                <li>
                  <t>If <tt>membership</tt> is <tt>knock</tt>:      </t>
                  <ol spacing="normal" type="1"><li>If the <tt>join_rule</tt> for <tt>m.room.join_rules</tt> is anything other than <tt>knock</tt>, reject.</li>
                    <li>If the <tt>sender</tt> does not match the <tt>state_key</tt>, reject.</li>
                    <li>If the <tt>sender</tt>'s current membership state is not <tt>ban</tt> or <tt>join</tt>, allow.</li>
                    <li>Otherwise, reject.</li>
                  </ol>
                </li>
                <li>Otherwise, the <tt>membership</tt> is unknown. Reject.</li>
              </ol>
            </li>
            <li>If the <tt>sender</tt>'s current membership state is not <tt>join</tt>, reject.</li>
            <li>If the event <tt>type</tt>'s required power level is greater than the <tt>sender</tt>'s power level,
reject.</li>
            <li>If the event has a <tt>state_key</tt> which starts with an <tt>@</tt> and does not match the <tt>sender</tt>,
reject.</li>
            <li>
              <t>If <tt>type</tt> is <tt>m.room.power_levels</tt>:  </t>
              <ol spacing="normal" type="1"><li>If any of the fields <tt>users_default</tt>, <tt>events_default</tt>, <tt>state_default</tt>, <tt>ban</tt>, <tt>redact</tt>,
<tt>kick</tt>, or <tt>invite</tt> in <tt>content</tt> are present and not an integer, reject.</li>
                <li>If <tt>events</tt> in <tt>content</tt> is present and not an object with values that are integers,
reject.</li>
                <li>If the <tt>users</tt> in <tt>content</tt> is present and not an object with valid user IDs as keys and
integers as values, reject.</li>
                <li>If there is no previous <tt>m.room.power_levels</tt> event in the room, allow.</li>
                <li>
                  <t>For the fields <tt>users_default</tt>, <tt>events_default</tt>, <tt>state_default</tt>, <tt>ban</tt>, <tt>redact</tt>, <tt>kick</tt>,
and <tt>invite</tt>, check if they were added, changed, or removed. For each found alteration:      </t>
                  <ol spacing="normal" type="1"><li>If the current value is higher than the <tt>sender</tt>'s current power level, reject.</li>
                    <li>If the new value is higher than the <tt>sender</tt>'s current power level, reject.</li>
                  </ol>
                </li>
                <li>
                  <t>For each entry being changed in or removed from <tt>events</tt>:      </t>
                  <ol spacing="normal" type="1"><li>If the current value is higher than the <tt>sender</tt>'s current power level, reject.</li>
                  </ol>
                </li>
                <li>
                  <t>For each entry being added to or changed in <tt>events</tt>:      </t>
                  <ol spacing="normal" type="1"><li>If the new value is greater than the <tt>sender</tt>'s current power level, reject.</li>
                  </ol>
                </li>
                <li>
                  <t>For each entry being changed in or removed from <tt>users</tt>, other than the <tt>sender</tt>'s own
entry:      </t>
                  <ol spacing="normal" type="1"><li>If the current value is higher than the <tt>sender</tt>'s current power level, reject.</li>
                  </ol>
                </li>
                <li>
                  <t>For each entry being added to or changed in <tt>users</tt>:      </t>
                  <ol spacing="normal" type="1"><li>If the new value is greater than the <tt>sender</tt>'s current power level, reject.</li>
                  </ol>
                </li>
                <li>Otherwise, allow.</li>
              </ol>
            </li>
            <li>Otherwise, allow.</li>
          </ol>
          <t>There are some consequences to these rules:</t>
          <ul spacing="normal">
            <li>Unless you are already a member of the room, the only permitted operations (aside from
the initial create/join) are being able to join public rooms, accept invites to rooms,
and reject invites to rooms.</li>
            <li>To unban another user, the sender must have a power level greater than or equal to both
the kick and ban power levels, <em>and</em> greater than the target user's power level.</li>
          </ul>
          <t><strong>TODO</strong>: If we want to enforce a single hub in a room, we'd do so here with auth rules.</t>
        </section>
      </section>
      <section anchor="signing">
        <name>Signing</name>
        <t>All servers, including hubs and participants, publish an ed25519 <xref target="RFC8032"/> signing key
to be used by other servers when verifying signatures.</t>
        <t><strong>TODO</strong>: Verify RFC reference. We might be using a slightly different ed25519 key today?
See https://hdevalence.ca/blog/2020-10-04-its-25519am</t>
        <section anchor="canonical-json">
          <name>Canonical JSON</name>
          <t>When signing a JSON object, such as an event, it is important that the bytes be ordered in
the same way for everyone. Otherwise, the signatures will never match.</t>
          <t>To canonicalize a JSON object, use <xref target="RFC8785"/>.</t>
          <t><strong>TODO</strong>: Matrix currently doesn't use RFC8785, but it should (or similar).</t>
        </section>
        <section anchor="signing-arbitrary-objects">
          <name>Signing arbitrary objects</name>
          <t>Though events receive a lot of signing, it is often necessary for a server to sign arbitary,
non-event, payloads as well. For example, in Matrix's existing HTTPS+JSON transport, requests
are signed to ensure they came from the source they claim to be.</t>
          <t>To sign an object, the JSON is canonically encoded without the <tt>signatures</tt> or <tt>unsigned</tt>
fields. The bytes of the canonically encoded JSON are then signed using the ed25519 signing
key for the server. The resulting signature is then encoded using unpadded base64.</t>
        </section>
        <section anchor="signing-events">
          <name>Signing events</name>
          <t>Signing events is very similar to signing an arbitary object, however with a note that an event
is first redacted before signing. This ensures that later if the event were to be redacted in
the room that the signature check still passes.</t>
          <t>Note that the content hash covers the event's contents in case of redaction.</t>
          <section anchor="redacting-an-event">
            <name>Redacting an event</name>
            <t>All fields at the top level except the following are stripped from the event:</t>
            <ul spacing="normal">
              <li>
                <tt>type</tt></li>
              <li>
                <tt>room_id</tt></li>
              <li>
                <tt>sender</tt></li>
              <li>
                <tt>state_key</tt></li>
              <li>
                <tt>content</tt></li>
              <li>
                <tt>origin_server_ts</tt></li>
              <li>
                <tt>hashes</tt></li>
              <li>
                <tt>signatures</tt></li>
              <li>
                <tt>prev_events</tt></li>
              <li>
                <tt>auth_events</tt></li>
              <li>
                <tt>hub_server</tt></li>
            </ul>
            <t>Additionally, some event types retain specific fields under the event's <tt>content</tt>. All other
fields are stripped.</t>
            <ul spacing="normal">
              <li>
                <tt>m.room.create</tt> retains all fields in <tt>content</tt>.</li>
              <li>
                <tt>m.room.member</tt> retains <tt>membership</tt>.</li>
              <li>
                <tt>m.room.join_rules</tt> retains <tt>join_rule</tt>.</li>
              <li>
                <tt>m.room.power_levels</tt> retains <tt>ban</tt>, <tt>events</tt>, <tt>events_default</tt>, <tt>kick</tt>, <tt>redact</tt>, <tt>state_default</tt>,
<tt>users</tt>, <tt>users_default</tt>, and <tt>invite</tt>.</li>
              <li>
                <tt>m.room.history_visibility</tt> retains <tt>history_visibility</tt>.</li>
            </ul>
          </section>
        </section>
        <section anchor="checking-a-signature">
          <name>Checking a signature</name>
          <t>If the <tt>signatures</tt> field is missing, doesn't contain the entity that is expected to have done
the signing (a server name), doesn't have a known key ID, or is otherwise structurally invalid
then the signature check fails.</t>
          <t>If decoding the base64 fails, the check fails.</t>
          <t>If removing the <tt>signatures</tt> and <tt>unsigned</tt> properties, canonicalizing the JSON, and verifying
the signature fails, the check fails.</t>
          <t>Otherwise, the check passes.</t>
        </section>
      </section>
      <section anchor="hashes">
        <name>Hashes</name>
        <t>An event is covered by two hashes: a content hash and a reference hash. The content hash covers the
unredacted event to ensure it was not modified in transit. The reference hash covers the essential
fields of the event, including content hashes, and serves as the event's ID.</t>
        <section anchor="content-hash-calculation">
          <name>Content hash calculation</name>
          <ol spacing="normal" type="1"><li>Remove any existing <tt>unsigned</tt>, <tt>signatures</tt>, and <tt>hashes</tt> fields.</li>
            <li>Encode the object using canonical JSON.</li>
            <li>Hash the resulting bytes with SHA-256 <xref target="RFC6234"/>.</li>
            <li>Encode the hash using unpadded base64.</li>
          </ol>
        </section>
        <section anchor="reference-hash">
          <name>Reference hash</name>
          <ol spacing="normal" type="1"><li>Redact the event.</li>
            <li>Remove <tt>signatures</tt> and <tt>unsigned</tt> fields.</li>
            <li>Encode the object using canonical JSON.</li>
            <li>Hash the resulting bytes with SHA-256 <xref target="RFC6234"/>.</li>
            <li>Encode the hash using URL-safe unpadded base64.</li>
          </ol>
        </section>
      </section>
      <section anchor="unpadded-base64">
        <name>Unpadded Base64</name>
        <t>Throughout this document, "unpadded base64" is used to represent binary values as strings. Base64 is
as specified by <xref target="RFC4648"/>, and <em>unpadded</em> base64 simply removes any <tt>=</tt> padding from the resulting
string.</t>
        <t>Implementations SHOULD accept input with or without padding on base64 values.</t>
        <t>Section 5 of <xref target="RFC4648"/> describes <em>URL-safe</em> base64. The same changes are adopted here. Namely, the
62nd and 63rd characters are replaced with <tt>-</tt> and <tt>_</tt> respectively. The unpadded behaviour is as
described above.</t>
      </section>
    </section>
    <section anchor="hub-transfers">
      <name>Hub transfers</name>
      <t><strong>TODO</strong>: This section, if we want a single canonical hub in the room. Some expected problems in this
area are: who signs the transfer event? who <em>sends</em> the transfer event? how does a transfer start?</t>
      <t><strong>TODO</strong>: Is this section better placed in the MSC for now?</t>
    </section>
    <section anchor="transport">
      <name>Transport</name>
      <t><strong>TODO</strong>: This section, though this is likely (should be?) to be a dedicated I-D.</t>
      <t>Topics:
* Server discovery
* Publishing of signing keys
* Sending events between servers
* Media handling
* etc</t>
      <t>Matrix currently uses an HTTPS+JSON transport for this.</t>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t><strong>TODO</strong>: Expand upon this section.</t>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>The <tt>m.*</tt> namespace likely needs formal registration in some capacity.</t>
    </section>
  </middle>
  <back>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>
        <reference anchor="I-D.ralston-mimi-terminology">
          <front>
            <title>MIMI Terminology</title>
            <author fullname="Travis Ralston" initials="T." surname="Ralston">
              <organization>The Matrix.org Foundation C.I.C.</organization>
            </author>
            <date day="11" month="April" year="2023"/>
            <abstract>
              <t>   This document introduces a set of terminology to use when discussing
   or describing concepts within MIMI.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ralston-mimi-terminology-00"/>
        </reference>
        <reference anchor="RFC1123">
          <front>
            <title>Requirements for Internet Hosts - Application and Support</title>
            <author fullname="R. Braden" initials="R." role="editor" surname="Braden">
              <organization/>
            </author>
            <date month="October" year="1989"/>
            <abstract>
              <t>This RFC is an official specification for the Internet community.  It incorporates by reference, amends, corrects, and supplements the primary protocol standards documents relating to hosts.  [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="STD" value="3"/>
          <seriesInfo name="RFC" value="1123"/>
          <seriesInfo name="DOI" value="10.17487/RFC1123"/>
        </reference>
        <reference anchor="RFC3629">
          <front>
            <title>UTF-8, a transformation format of ISO 10646</title>
            <author fullname="F. Yergeau" initials="F." surname="Yergeau">
              <organization/>
            </author>
            <date month="November" year="2003"/>
            <abstract>
              <t>ISO/IEC 10646-1 defines a large character set called the Universal Character Set (UCS) which encompasses most of the world's writing systems.  The originally proposed encodings of the UCS, however, were not compatible with many current applications and protocols, and this has led to the development of UTF-8, the object of this memo.  UTF-8 has the characteristic of preserving the full US-ASCII range, providing compatibility with file systems, parsers and other software that rely on US-ASCII values but are transparent to other values.  This memo obsoletes and replaces RFC 2279.</t>
            </abstract>
          </front>
          <seriesInfo name="STD" value="63"/>
          <seriesInfo name="RFC" value="3629"/>
          <seriesInfo name="DOI" value="10.17487/RFC3629"/>
        </reference>
        <reference anchor="RFC8259">
          <front>
            <title>The JavaScript Object Notation (JSON) Data Interchange Format</title>
            <author fullname="T. Bray" initials="T." role="editor" surname="Bray">
              <organization/>
            </author>
            <date month="December" year="2017"/>
            <abstract>
              <t>JavaScript Object Notation (JSON) is a lightweight, text-based, language-independent data interchange format.  It was derived from the ECMAScript Programming Language Standard.  JSON defines a small set of formatting rules for the portable representation of structured data.</t>
              <t>This document removes inconsistencies with other specifications of JSON, repairs specification errors, and offers experience-based interoperability guidance.</t>
            </abstract>
          </front>
          <seriesInfo name="STD" value="90"/>
          <seriesInfo name="RFC" value="8259"/>
          <seriesInfo name="DOI" value="10.17487/RFC8259"/>
        </reference>
        <reference anchor="RFC8032">
          <front>
            <title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title>
            <author fullname="S. Josefsson" initials="S." surname="Josefsson">
              <organization/>
            </author>
            <author fullname="I. Liusvaara" initials="I." surname="Liusvaara">
              <organization/>
            </author>
            <date month="January" year="2017"/>
            <abstract>
              <t>This document describes elliptic curve signature scheme Edwards-curve Digital Signature Algorithm (EdDSA).  The algorithm is instantiated with recommended parameters for the edwards25519 and edwards448 curves.  An example implementation and test vectors are provided.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="8032"/>
          <seriesInfo name="DOI" value="10.17487/RFC8032"/>
        </reference>
        <reference anchor="RFC8785">
          <front>
            <title>JSON Canonicalization Scheme (JCS)</title>
            <author fullname="A. Rundgren" initials="A." surname="Rundgren">
              <organization/>
            </author>
            <author fullname="B. Jordan" initials="B." surname="Jordan">
              <organization/>
            </author>
            <author fullname="S. Erdtman" initials="S." surname="Erdtman">
              <organization/>
            </author>
            <date month="June" year="2020"/>
            <abstract>
              <t>Cryptographic operations like hashing and signing need the data to be expressed in an invariant format so that the operations are reliably repeatable.  One way to address this is to create a canonical representation of the data.  Canonicalization also permits data to be exchanged in its original form on the "wire" while cryptographic operations performed on the canonicalized counterpart of the data in the producer and consumer endpoints generate consistent results. </t>
              <t>This document describes the JSON Canonicalization Scheme (JCS). This specification defines how to create a canonical representation of JSON data by building on the strict serialization methods for JSON primitives defined by ECMAScript, constraining JSON data to the Internet JSON (I-JSON) subset, and by using deterministic property sorting.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="8785"/>
          <seriesInfo name="DOI" value="10.17487/RFC8785"/>
        </reference>
        <reference anchor="RFC6234">
          <front>
            <title>US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)</title>
            <author fullname="D. Eastlake 3rd" initials="D." surname="Eastlake 3rd">
              <organization/>
            </author>
            <author fullname="T. Hansen" initials="T." surname="Hansen">
              <organization/>
            </author>
            <date month="May" year="2011"/>
            <abstract>
              <t>Federal Information Processing Standard, FIPS</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="6234"/>
          <seriesInfo name="DOI" value="10.17487/RFC6234"/>
        </reference>
        <reference anchor="RFC4648">
          <front>
            <title>The Base16, Base32, and Base64 Data Encodings</title>
            <author fullname="S. Josefsson" initials="S." surname="Josefsson">
              <organization/>
            </author>
            <date month="October" year="2006"/>
            <abstract>
              <t>This document describes the commonly used base 64, base 32, and base 16 encoding schemes.  It also discusses the use of line-feeds in encoded data, use of padding in encoded data, use of non-alphabet characters in encoded data, use of different encoding alphabets, and canonical encodings.  [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="4648"/>
          <seriesInfo name="DOI" value="10.17487/RFC4648"/>
        </reference>
      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="MSC3995" target="https://github.com/matrix-org/matrix-spec-proposals/pull/3995">
          <front>
            <title>MSC3995: [WIP] Linearized Matrix</title>
            <author fullname="Travis Ralston">
              <organization>The Matrix.org Foundation C.I.C.</organization>
            </author>
            <date year="2023" month="April" day="12"/>
          </front>
        </reference>
        <reference anchor="DMLS" target="https://gitlab.matrix.org/matrix-org/mls-ts/-/blob/48efb972075233c3a0f3e3ca01c4d4f888342205/decentralised.org">
          <front>
            <title>Decentralised MLS</title>
            <author fullname="Hubert Chathi">
              <organization>The Matrix.org Foundation C.I.C.</organization>
            </author>
            <date year="2023" month="May" day="29"/>
          </front>
        </reference>
      </references>
    </references>
    <?line 871?>

<section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>Thank you to the Matrix Spec Core Team (SCT), and in particular Richard van der Hoff, for
exploring how Matrix rooms could be represented as a linear structure, leading to this document.</t>
    </section>
  </back>
  <!-- ##markdown-source:
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

-->

</rfc>
