Original text:
9. <del> In order to facilitate the asynchronous addition of clients to a group, key packages are pre-published that provide some public information about a user.  A KeyPackage object specifies: A protocol version and ciphersuite that the client supports, a public key that others can use for key agreement, a credential authenticating the client's application-layer identity, and an "endpoint_id" that uniquely identifies a client in a group. KeyPackages are intended to be used only once and SHOULD NOT be reused except in case of last resort.  (See keypackage-reuse). Clients MAY generate and publish multiple KeyPackages to support multiple ciphersuites. The value for hpke_init_key MUST be a public key for the asymmetric encryption scheme defined by cipher_suite, and it MUST be unique among the set of KeyPackages created by this client.  The whole structure is signed using the client's signature key.  A KeyPackage object with an invalid signature field MUST be considered malformed. The signature is computed by the function "SignWithLabel" with a label "KeyPackage" and a content comprising of all of the fields except for the signature field. KeyPackage objects MUST contain at least two extensions, one of type "capabilities", and one of type "lifetime".  The "capabilities" extension allows MLS session establishment to be safe from downgrade attacks on the parameters described (as discussed in group-creation), while still only advertising one version / ciphersuite per KeyPackage. As the "KeyPackage" is a structure which is stored in the Ratchet Tree and updated depending on the evolution of the tree, each modification of its content MUST be reflected by a change in its signature.  This allows other members to verify the validity of the KeyPackage at any time, particularly in the case of a newcomer joining the group. 9.1. The validity of a KeyPackage needs to be verified at a few stages: When a KeyPackage is downloaded by a group member, before it is used to add the client to the group When a KeyPackage is received by a group member in an Add, Update, or Commit message When a client joining a group receives KeyPackages for the other members of the group in the group's ratchet tree The client verifies the validity of a KeyPackage using the following steps: Verify that the credential in the KeyPackage is valid according to the authentication service and the client's local policy.  These actions MUST be the same regardless of at what point in the protocol the KeyPackage is being verified. Verify that the signature on the KeyPackage is valid using the public key in the KeyPackage's credential Verify that the KeyPackage is compatible with the group's parameters.  The ciphersuite and protocol version of the KeyPackage must match those in use in the group.  If the GroupContext has a "required_capabilities" extension, then the required extensions and proposals MUST be listed in the KeyPackage's "capabilities" extension. Verify that the following fields in the KeyPackage are unique among the members of the group (including any other members added in the same Commit): "credential.signature_key" "hpke_init_key" "endpoint_id" 9.2. The "capabilities" extension indicates what protocol versions, ciphersuites, protocol extensions, and non-default proposal types are supported by a client.  Proposal types defined in this document are considered "default" and thus need not be listed. This extension MUST be always present in a KeyPackage.  Extensions that appear in the "extensions" field of a KeyPackage MUST be included in the "extensions" field of the "capabilities" extension. 9.3. The "lifetime" extension represents the times between which clients will consider a KeyPackage valid.  This time is represented as an absolute time, measured in seconds since the Unix epoch (1970-01-01T00:00:00Z).  A client MUST NOT use the data in a KeyPackage for any processing before the "not_before" date, or after the "not_after" date. Applications MUST define a maximum total lifetime that is acceptable for a KeyPackage, and reject any KeyPackage where the total lifetime is longer than this duration. This extension MUST always be present in a KeyPackage. 9.4. Within MLS, a KeyPackage is identified by its hash (see, e.g., joining-via-welcome-message).  The "external_key_id" extension allows applications to add an explicit, application-defined identifier to a KeyPackage. 9.5. Each member of the group maintains a GroupContext object that summarizes the state of the group: The fields in this state have the following semantics: The "group_id" field is an application-defined identifier for the group. The "epoch" field represents the current version of the group key. The "tree_hash" field contains a commitment to the contents of the group's ratchet tree and the credentials for the members of the group, as described in tree-hashes. The "confirmed_transcript_hash" field contains a running hash over the messages that led to this state. The "extensions" field contains the details of any protocol extensions that apply to the group. When a new member is added to the group, an existing member of the group provides the new member with a Welcome message.  The Welcome message provides the information the new member needs to initialize its GroupContext. Different changes to the group will have different effects on the group state.  These effects are described in their respective subsections of proposals.  The following general rules apply: The "group_id" field is constant. The "epoch" field increments by one for each Commit message that is processed. The "tree_hash" is updated to represent the current tree and credentials. The "confirmed_transcript_hash" field is updated with the data for an MLSPlaintext message encoding a Commit message as described below. The "extensions" field changes when a GroupContextExtensions proposal is committed. The "confirmed_transcript_hash" is updated with an MLSPlaintext in two steps: Thus the "confirmed_transcript_hash" field in a GroupContext object represents a transcript over the whole history of MLSPlaintext Commit messages, up to the confirmation_tag field of the most recent Commit. The confirmation tag is then included in the transcript for the next epoch.  The interim transcript hash is computed by new members using the confirmation_tag of the GroupInfo struct, while existing members can compute it directly. As shown above, when a new group is created, the "interim_transcript_hash" field is set to the zero-length octet string. 10. </del> Group keys are derived using the "Extract" and "Expand" functions from the KDF for the group's ciphersuite, as well as the functions defined below: GroupInfo struct in order to allow non-members to join the group using an external commit. <del> 10.1. </del>  In addition to initializing a new epoch via KDF invocations as described above, an MLS group can also initialize a new epoch via an PublicGroupState for the previous epoch, encoded using the TLS serialization. <del> 10.2. </del>  Groups which already have an out-of-band mechanism to generate shared group secrets can inject those into the MLS key schedule to seed the Commit, then the resulting "psk_secret" is "psk_secret_[0]", the all- zero vector. <del> 10.3. </del>  For the generation of encryption keys and nonces, the key schedule begins with the "encryption_secret" at the root and derives a tree of nonces are derived, as described in encryption-keys.  The root of each ratchet is computed as: <del> 10.4. </del>  As described in message-framing, MLS encrypts three different types of information: Here, AEAD.Nn and AEAD.Nk denote the lengths in bytes of the nonce and key for the AEAD scheme defined by the ciphersuite. <del> 10.5. </del>  It is important to delete all security-sensitive values as soon as they are _consumed_. A sensitive value S is said to be _consumed_ if (not consume) the values K0 and N0 to allow for out-of-order delivery, and SHOULD retain AR2 for processing future messages. <del> 10.6. </del>  The main MLS key schedule provides an "exporter_secret" which can be used by an application as the basis to derive new secrets called It is RECOMMENDED for the application generating exported values to refresh those values after a Commit is processed. <del> 10.7. </del>  The main MLS key schedule provides a "resumption_secret" that is used as a PSK to inject entropy from one epoch into another.  This the number of past epochs for which the "resumption_secret" may be stored. <del> 10.8. </del>  The main MLS key schedule provides a per-epoch "authentication_secret".  If one of the parties is being actively authentication protocol to ensure that they share the same view of the group.  11. A group is always created with a single member, the "creator".  The

Reviewer comments:
Depends on This swaps the "Key Packages" and "Key Schedule" sections, so that the former is just before "Group Creation".
Best reviewed with , which will show the diff against
This issue accompanies the e-mail [1] pointing out editorial issues with the draft and suggesting improvements. TL;DR: I don't think the draft currently is what is needed to implement MLS. It needs an editorial overhaul with a better structure. [1] URL
If we want an implementation document, which is a legitimate ask, we should write an implementation document.
What's the purpose of the document if not for implementation? In order for this draft to become an RFC it needs implementations. I don't see a way this will happen with the draft as is.
Specifying a functional behavior and providing a guide for implementation are two very different things. Re: what you suggested in your email: Internal representations of the tree, the way you number the indices, how you implement them or the fact that you store some hashes in the nodes are completely irrelevant to this document. Also, there is nothing formal about this appendix. On the other hand the information you need from this document is how to perform computations : things such as providing the arguments to the nodeencap/nodedecap functions which are required to generate a correct payload and a standard way to serialize abstract structures... etc.
Right, the document is doing neither right now.
We have two separable issues here: We need better explanation of the overall structure of the protocol (as in Franziskus' email), and we could rearrange the text to be clearer. For the first, I have filed . That provides a pretty complete overview of the protocol, covering all of the syntax and high-level operations. For the second, we should do a second PR after the other outstanding PRs have landed. Looking at the table of contents, I would propose we refactor in the following way: For top-level sections: Move to after and For subsections: Move the tree-relevant subsections of into — including , , and Split into two: Put the GroupContext definition part in a new subsection under Put the transcript updating part in a new subsection under
I have an alternative organization of the first sections: Add the one sentence definition of before the last paragraph of Swap and This seems to all flow nicely with very few forward references. A more radical rewrite might Move forward before but I don't think that is necessary. I do like Richard's proposal to split
I'm considering this fixed after the series of reorg PRs that NAME NAME and I just finished. Hi all, While trying to implement the MLS protocol from scratch I ran into a couple issues and I think there’s a general problem regarding the structure of the draft. Note that these are all editorial issues. Right now I see no straightforward way to implement the spec as there’s no clear structure. To implement even the basic tree structure it’s necessary to jump through the entire document. There’s also a lot of prose and examples and very little implementable parts. Let me give some examples: Section 5 (Ratchet Trees) reads like a non-normative section (or paper). The really interesting bit related to trees is in Appendix A. I suggest moving the formal description of the tree from Appendix A to this section. It’s impossible to implement this from the hand full examples here. There’s no description in here on how the tree actually works. For example, adding a node to the tree is defined in 10.1.1 (Add). The ratchet tree nodes as described in Section 5 don't hold a KeyPackage. But Section 7 says “As the KeyPackage is a structure which is stored in the Ratchet Tree and updated depending on the evolution of this tree”. The tree nodes have a parent hash field, which is of course part of the ratchet tree but shouldn’t be necessary for the description of the tree structure. Also, the description of the tree hash (Section 7.5) follows the definition of the parenthash extension in Section 7.4 such that it is not entirely clear which parenthash is used there (extension or node value). Section 5 also talks about commit messages without linking to them or introducing them. Having to talk about commit messages in this section is also a little confusing. The term “handshake message” is first used in Section 7.8 (Key Schedule) but never introduced. This should probably happen in 10 (Group Evolution), which doesn’t talk about handshake messages at all until 10.3 (Ratchet Tree Extension). There are probably plenty more issues like this. But I don’t think addressing any of these issues individually makes sense. I therefore suggest having an overhaul of the document structure. The way I see MLS there are a set of high-level structures and components that should be clearly described and built upon each other. There’s a data structure (tree) that is used to represent a group. Then there is the MLS group that implements a specific semantic on the tree. Operations to modify the group are specified in the handshake protocol. And application messages define messages encrypted with keys derived in the handshake protocol with the key schedule. The tree is a basic left-balanced binary tree and defines functions to create a tree, and add and remove nodes. A group is the main part of MLS, a tree with nodes of a certain type. So this part should describe what nodes look like and how the tree is used to compute tree invariants and keys. The handshake protocol defines all messages needed to perform operations on the MLS group. This is certainly not exhaustive and would need further refinement. But it’s the high-level structure I’d expect from the document. I’m sure other structures would work as well. But what we currently have isn’t what is needed to implement MLS imho. Cheers, Franziskus

Revised text:
9.  Group keys are derived using the "Extract" and "Expand" functions from the KDF for the group's ciphersuite, as well as the functions defined below: GroupInfo struct in order to allow non-members to join the group using an external commit.  <ins> 9.1. </ins> In addition to initializing a new epoch via KDF invocations as described above, an MLS group can also initialize a new epoch via an PublicGroupState for the previous epoch, encoded using the TLS serialization.  <ins> 9.2. </ins> Groups which already have an out-of-band mechanism to generate shared group secrets can inject those into the MLS key schedule to seed the Commit, then the resulting "psk_secret" is "psk_secret_[0]", the all- zero vector.  <ins> 9.3. </ins> For the generation of encryption keys and nonces, the key schedule begins with the "encryption_secret" at the root and derives a tree of nonces are derived, as described in encryption-keys.  The root of each ratchet is computed as:  <ins> 9.4. </ins> As described in message-framing, MLS encrypts three different types of information: Here, AEAD.Nn and AEAD.Nk denote the lengths in bytes of the nonce and key for the AEAD scheme defined by the ciphersuite.  <ins> 9.5. </ins> It is important to delete all security-sensitive values as soon as they are _consumed_. A sensitive value S is said to be _consumed_ if (not consume) the values K0 and N0 to allow for out-of-order delivery, and SHOULD retain AR2 for processing future messages.  <ins> 9.6. </ins> The main MLS key schedule provides an "exporter_secret" which can be used by an application as the basis to derive new secrets called It is RECOMMENDED for the application generating exported values to refresh those values after a Commit is processed.  <ins> 9.7. </ins> The main MLS key schedule provides a "resumption_secret" that is used as a PSK to inject entropy from one epoch into another.  This the number of past epochs for which the "resumption_secret" may be stored.  <ins> 9.8. </ins> The main MLS key schedule provides a per-epoch "authentication_secret".  If one of the parties is being actively authentication protocol to ensure that they share the same view of the group. <ins> 10. In order to facilitate the asynchronous addition of clients to a group, key packages are pre-published that provide some public information about a user.  A KeyPackage object specifies: A protocol version and ciphersuite that the client supports, a public key that others can use for key agreement, a credential authenticating the client's application-layer identity, and an "endpoint_id" that uniquely identifies a client in a group. KeyPackages are intended to be used only once and SHOULD NOT be reused except in case of last resort.  (See keypackage-reuse). Clients MAY generate and publish multiple KeyPackages to support multiple ciphersuites. The value for hpke_init_key MUST be a public key for the asymmetric encryption scheme defined by cipher_suite, and it MUST be unique among the set of KeyPackages created by this client.  The whole structure is signed using the client's signature key.  A KeyPackage object with an invalid signature field MUST be considered malformed. The signature is computed by the function "SignWithLabel" with a label "KeyPackage" and a content comprising of all of the fields except for the signature field. KeyPackage objects MUST contain at least two extensions, one of type "capabilities", and one of type "lifetime".  The "capabilities" extension allows MLS session establishment to be safe from downgrade attacks on the parameters described (as discussed in group-creation), while still only advertising one version / ciphersuite per KeyPackage. As the "KeyPackage" is a structure which is stored in the Ratchet Tree and updated depending on the evolution of the tree, each modification of its content MUST be reflected by a change in its signature.  This allows other members to verify the validity of the KeyPackage at any time, particularly in the case of a newcomer joining the group. 10.1. The validity of a KeyPackage needs to be verified at a few stages: When a KeyPackage is downloaded by a group member, before it is used to add the client to the group When a KeyPackage is received by a group member in an Add, Update, or Commit message When a client joining a group receives KeyPackages for the other members of the group in the group's ratchet tree The client verifies the validity of a KeyPackage using the following steps: Verify that the credential in the KeyPackage is valid according to the authentication service and the client's local policy.  These actions MUST be the same regardless of at what point in the protocol the KeyPackage is being verified. Verify that the signature on the KeyPackage is valid using the public key in the KeyPackage's credential Verify that the KeyPackage is compatible with the group's parameters.  The ciphersuite and protocol version of the KeyPackage must match those in use in the group.  If the GroupContext has a "required_capabilities" extension, then the required extensions and proposals MUST be listed in the KeyPackage's "capabilities" extension. Verify that the following fields in the KeyPackage are unique among the members of the group (including any other members added in the same Commit): "credential.signature_key" "hpke_init_key" "endpoint_id" 10.2. The "capabilities" extension indicates what protocol versions, ciphersuites, protocol extensions, and non-default proposal types are supported by a client.  Proposal types defined in this document are considered "default" and thus need not be listed. This extension MUST be always present in a KeyPackage.  Extensions that appear in the "extensions" field of a KeyPackage MUST be included in the "extensions" field of the "capabilities" extension. 10.3. The "lifetime" extension represents the times between which clients will consider a KeyPackage valid.  This time is represented as an absolute time, measured in seconds since the Unix epoch (1970-01-01T00:00:00Z).  A client MUST NOT use the data in a KeyPackage for any processing before the "not_before" date, or after the "not_after" date. Applications MUST define a maximum total lifetime that is acceptable for a KeyPackage, and reject any KeyPackage where the total lifetime is longer than this duration. This extension MUST always be present in a KeyPackage. 10.4. Within MLS, a KeyPackage is identified by its hash (see, e.g., joining-via-welcome-message).  The "external_key_id" extension allows applications to add an explicit, application-defined identifier to a KeyPackage. 10.5. Each member of the group maintains a GroupContext object that summarizes the state of the group: The fields in this state have the following semantics: The "group_id" field is an application-defined identifier for the group. The "epoch" field represents the current version of the group key. The "tree_hash" field contains a commitment to the contents of the group's ratchet tree and the credentials for the members of the group, as described in tree-hashes. The "confirmed_transcript_hash" field contains a running hash over the messages that led to this state. The "extensions" field contains the details of any protocol extensions that apply to the group. When a new member is added to the group, an existing member of the group provides the new member with a Welcome message.  The Welcome message provides the information the new member needs to initialize its GroupContext. Different changes to the group will have different effects on the group state.  These effects are described in their respective subsections of proposals.  The following general rules apply: The "group_id" field is constant. The "epoch" field increments by one for each Commit message that is processed. The "tree_hash" is updated to represent the current tree and credentials. The "confirmed_transcript_hash" field is updated with the data for an MLSPlaintext message encoding a Commit message as described below. The "extensions" field changes when a GroupContextExtensions proposal is committed. The "confirmed_transcript_hash" is updated with an MLSPlaintext in two steps: Thus the "confirmed_transcript_hash" field in a GroupContext object represents a transcript over the whole history of MLSPlaintext Commit messages, up to the confirmation_tag field of the most recent Commit. The confirmation tag is then included in the transcript for the next epoch.  The interim transcript hash is computed by new members using the confirmation_tag of the GroupInfo struct, while existing members can compute it directly. As shown above, when a new group is created, the "interim_transcript_hash" field is set to the zero-length octet string. </ins> 11. A group is always created with a single member, the "creator".  The