Change:
Puncture tree heads are nodes that are OK whose parents are not OK <del> [[ Following sections to be filled from earlier PDF/code + diffs from the London meeting ]] </del> 5. <ins> Logically, the state of an MLS group at a given time comprises: A group ID A ciphersuite used for cryptographic computations A Merkle tree over the participants' identity keys A ratchet tree over the participants' leaf key pairs A message root key (known only to participants) An add key pair (private key known only to participants) An init secret (known only to participants) Since a group can evolve over time, a session logically comprises a sequence of states.  The time in which each individual state is used is called an "epoch", and each state is assigned an epoch number that increments when the state changes. MLS handshake message provide each node with enough information about the trees to authenticate messages within the group and compute the group secrets. Thus, each participant will need store the following information about each state of the group: The participant's index in the identity/ratchet trees The private key for the participant's leaf key pair The private key for the participant's identity key pair The current epoch number The group ID A subset of the identity tree comprising at least the copath for the participant's leaf A subset of the ratchet tree comprising at least the copath for the participant's leaf The current message root key The current update key pair The current init secret 5.1. Each MLS session uses a single cipher suite that specifies the following values to be used in group key computations: A hash function A Diffie-Hellman group Public keys used in the protocol are opaque values in a format defined by the ciphersuite. 5.2. Group keys are derived using the HKDF-Extract and HKDF-Expand functions as defined in RFC5869, as well as the functions defined below: The Hash function used by HKDF is the cipher suite hash algorithm. Hash.length is its output length in bytes.  In the below diagram: HKDF-Extract takes its Salt argument form the top and its IKM argument from the left Derive-Secret takes its Secret argument from the incoming arrow When processing a handshake message, a participant combines the following information to derive new epoch secrets: The init secret from the previous epoch The update secret for the current epoch The handshake message that caused the epoch change The current group ID and epoch The derivation of the epoch key pair depends on the change being made.  For the first epoch, when there is no previous epoch key pair, the creator of the group generates a fresh key pair and publishes it to the initial set of participants. Given these inputs, the derivation of secrets for an epoch proceeds as shown in the following diagram: </ins> 6. <ins> In order to facilitate asynchronous addition of participants to a group, it is possible to pre-publish initialization keys that provide some public information about a user or group.  UserInitKey messages provide information a user that a group member can use to add the user to a group without the user being online.  GroupInitKey messages provide information about a group that a new user can use to join the group without any of the existing members of the group being online. </ins> 6.1. <ins> A UserInitKey object specifies what cipher suites a client supports, as well as providing public keys that the client can use for key derivation and signing.  The client's identity key is intended to be stable through the lifetime of the group; there is no mechanism to change it.  Init keys are intend to be used one time only (or perhaps a small number of times, see #init-key-reuse). The init_keys array MUST have the same length as the cipher_suites array, and each entry in the init_keys array MUST be a public key for the DH group defined by the corresponding entry in the cipher_suites array. The whole structure is signed using the client's identity key.  A UserInitKey object with an invalid signature field MUST be considered mal-formed.  The input to the signature computation comprises all of the fields except for the signture field. </ins> 6.2. <del> 6.3. </del> <ins> A GroupInitKey object specifies the aspects of a group's state that a new member needs to initialize its state (together with an identity key and a fresh leaf key pair). The current epoch number The number of participants currently in the group The group ID The cipher suite used by the group The public key of the current update key pair for the group </ins> <del> 6.4. </del> <ins> The frontier of the identity tree, as a sequence of hash values </ins> <del> 6.5. </del> <ins> The frontier of the ratchet tree, as a sequence of public keys </ins> <del> 6.6. </del> <ins> GroupInitKey messages are not themselves signed.  A GroupInitKey should not be published "bare"; instead, it should be published by constructing a handshake message with type "none", which will include a signature by a member of the group and a proof of membership in the group. </ins> 7. <ins> Over the lifetime of a group, changes need to be made to the group's state: Initializing a group A current member adding a new participant A new participant adding themselves A current participant updating its leaf key A current member deleting another current member In MLS, these changes are accomplished by broadcasting "handshake" messages to the group.  Note that unlike TLS and DTLS, there is not a consolidated handshake phase to the protocol.  Rather, handshake messages are exchanged throughout the lifetime of a group, whenever a change is made to the group state. An MLS handshake message encapsulates a specific message that accomplishes a change in group state, and also includes two other important features: First, it provides a GroupInitKey so that a new participant can observe the latest state of the handshake and initialize itself.  Second, it provides a signature by a member of the group, together with a Merle inclusion proof that demonstrates that the signer is a legitimate member of the group. Before considering a handshake message valid, the recipient MUST verify both that the signature is valid and that the Merkle inclusion proof is valid.  The input to the signature computations comprises the entire handshake message except for the signature field. The Merkle tree head to be used for validating the inclusion proof MUST be one that the recipient trusts to represent the current list of participant identity keys. 7.1. [[ Direct initialization is currently undefined.  A participant can create a group by initializing its own state to reflect a group including only itself, then adding the initial participants.  This has computation and communication complexity O(N log N) instead of the O(N) complexity of direct initialization. ]] 7.2. An GroupAdd message is sent by a group member to add a new participant to the group.  The contents of the message are simply the UserInitKey for the user being added. A group member generates such a message by downloading a UserInitKey for the user to be added.  The added participant processes the message together with the private key corresponding to the UserInitKey to initialize his state as follows: Compute the participant's leaf key pair by combining the init key in the UserInitKey with the prior epoch's update key pair Use the frontiers in the GroupPreKey of the Handshake message to add its keys to the trees An existing participant receiving a GroupAdd message first verifies the signature on the message, then verifies its identity proof against the identity tree held by the participant.  The participant then updates its state as follows: Compute the new participant's leaf key pair by combining the leaf key in the UserPreKey with the prior epoch add key pair Update the group's identity tree and ratchet tree with the new participant's information The update secret resulting from this change is the output of a DH computation between the private key for the root of the ratchet tree and the add public key from the previous epoch. [[ ALTERNATIVE: The sender could also generate the new participant's leaf using a fresh key pair, as opposed to a key pair derived from the prior epoch's secret.  This would reduce the "double-join" problem, at the cost of the GroupAdd having to include a new ratchet frontier. ]] 7.3. A UserAdd message is sent by a new group participant to add themselves to the group, based on having already had access to a GroupInitKey for the group. A new participant generates this message using the following steps: Fetch a GroupInitKey for the group Use the frontiers in the GroupPreKey to add its keys to the trees Compute the direct path from the new participant's leaf in the new ratchet tree (the add_path). An existing participant receiving a UserAdd first verifies the signature on the message, then verifies its identity inclusion proof against the updated identity tree expressed in the GroupPreKey of the Handshake message (since the signer is not included in the prior group state held by the existing participant).  The participant then updates its state as follows: Update trees with the descriptions in the new GroupInitKey Update the local ratchet tree with the add path in the UserAdd message, replacing any common nodes with the values in the add path The update secret resulting from this change is the secret for the root node of the ratchet tree. 7.4. An Update message is sent by a group participant to update its leaf key pair.  This operation provides post-compromise security with regard to the participant's prior leaf private key. The sender of an Update message creates it in the following way: Generate a fresh leaf key pair Compute its direct path in the current ratchet tree An existing participant receiving a Update message first verifies the signature on the message, then verifies its identity proof against the identity tree held by the participant.  The participant then updates its state as follows: Update the cached ratchet tree by replacing nodes in the direct path from the updated leaf with the corresponding nodes in the Update message The update secret resulting from this change is the secret for the root node of the ratchet tree. 7.5. A delete message is sent by a group member to remove one or more participants from the group. The sender of a Delete message creates it in the following way: Compute the ordered list of subtree heads by puncturing the deleted participants' leaves from the current ratchet tree Generate a fresh DH key pair and initialize a "delete path" to the one-element list containing that key pair For each subtree head in the list: Perform a DH computation between the subtree head's public key and the private key from the last key pair in the delete path Derive a DH key pair from the output of that DH computation Append the resulting key pair to the delete path The head field in the Delete message holds the public keys corresponding to the subtree heads.  The path field holds the public keys corresponding to the delete path, with the last element omitted (it is unnecessary).  As a result, the heads and path arrays MUST have the same length. Note that the sender of a Delete message must enough information about the ratchet tree so that it has all of the subtree heads resulting from the puncture operation.  This criterion is met if the sender has a copath for each of the deleted participants. An existing participant receiving a Delete message first verifies the signature on the message, then verifies its identity proof against the identity tree held by the participant.  The participant then updates its state as follows: Compute the ordered list of subtree heads by puncturing the deleted participants' leaves from the current ratchet tree Find a public key in the list of subtree heads for which the private key is known to the recipient Perform a DH computation between the known subtree head private key and the public key in the delete path at the same index For each remaining element in the list of subtree heads: Derive a DH key pair from the last DH output Perform a DH computation between the private key of the derived key pair with the subtree head's public key The update secret for this change is the last DH output from the delete path. 8. </ins> Each state-changing message is premised on a given starting state Thus, there is a need to deconflict if two messages are generated

Discussion:
This PR adds a pretty complete description of the protocol. The only major thing that's missing is , which should be straightforward-ish to construct. NAME want to take a stab at that?