Original text:
5. The protocol uses "ratchet trees" for deriving shared secrets among a <del> group of clients. </del>  5.1. A node in the tree may also be _blank_, indicating that no value is present at that node.  The _resolution_ of a node is an ordered list of non-blank nodes that collectively cover all non-blank descendants <del> of the node. </del>  The resolution of a non-blank node comprises the node itself, followed by its list of unmerged leaves, if any "merged" as they receive the private keys for nodes, as described in ratchet-tree-evolution.  5.4. A member of an MLS group advances the key schedule to provide forward secret is used to derive a new secret value for the corresponding node, from which the node's key pair is derived.  For example, suppose there is a group with four members, with C an unmerged leaf at node 5: MLS uses HPKE for public-key encryption I-D.irtf-cfrg-hpke.  The "DeriveKeyPair" function associated to the KEM for the ciphersuite <del> maps octet strings to HPKE key pairs. </del>  Ciphersuites are represented with the CipherSuite type.  HPKE public keys are opaque values in a format defined by the underlying protocol Blank the intermediate nodes along the path from "removed_index" to the root <del> Truncate the tree by reducing the size of tree until the rightmost non-blank leaf node </del>  11.1.4.

Reviewer comments:
The terminology used in these sections is different, so that it's unclear if they're descriptions of the same operation with different levels of detail or entirely different operations performed at different times. I come in having read most of the original white paper, so that my intuition is that it's one operation performed against data stored in the tree structure. As such, I'm unclear how the -> relates to the via the "number of secrets [that] are derived from the epoch secret for different purposes". Also, The Group Creation section makes no reference to any of these secrets by name. I would kind of expect something called, , to be involved during group creation, but it doesn't seem like that's necessary. is defined anywhere? Is it application level data to be included as desired?
Can you add the definition of definition to ?
In , in the diagram copied below, the label, "secret", is passed to DeriveTreeSecret(), where in the preceding section, it was either "application" or "handshake". This is intentional?
Could you specifically call out where the authentication tag created by AES-256-GCM is stored? Some implementations will need to find it and pass it in as a param to .
The group creation and external init parts of the doc each have discussions in two parts. It'd be easier to follow if they were consolidated. I would suggest moving the group creation section up to the other relevant parts and maybe introduce the other concepts in the context of group creation... that's how implementations would start.
I'm not sure why there needs to be two ratchets per leaf node. It seems like they never get ratcheted at the same time, and they both get reset during the same event(s).
It was easier for me to understand the concept as just a kind of depth first search through the sibling's tree, favoring the left child, for a public or private key. If building an update path follows the addition of empty nodes, then for each step up the tree, the sibling's tree is not going to have filled any new key pairs yet, so that conducting a search at that moment is only going to resolve a public key from the previous epoch.
What does this mean? Is part of the sentence missing?
Leaving it to applications to determine how many resumption secrets to maintain creates a problem with ExternalInit's. The external init is predicated entirely on public group state, so that the new member(s) will not have any resumption secrets from prior epochs as determined by the application. If one of those resumption secrets is employed, the group fractures. Moreover, I'm not seeing how one resumptionsecret alone is enough for a recovery operation... if that's one of its intended uses, which seems to be implied. There's not much to go on in the doc, but it seems to suggest the resumption secret is included in the key derivation schedule as a PSK. But the schedule also requires an initsecret and a commit_secret as inputs, which a recovering node cannot rely on to be in sync with the group.
For members, A, C, and D of a 4 member group, where A performed the additions of B,C, and D and then broadcast a Welcome message to all the others, their respective trees would look like the following after each adds their own private keys locally: denotes that a public/private key pair resides at node x If node performs an another tree update, e.g. adds another member, when computing the updatePath for node 3, it must select a public key from the subtree rooted at node 5 (the underscore). No key pair has been computed for node 5 yet, so that it would select the public key for node C and proceed. This, however, prevents node D from decrypting the pathsecret for node 3 because D does not know the private key for C. If A is to encrypt the pathsecret multiple times---each with a different key---what's the protocol? How many copies are enough? Does the number of copies have to grow with the size of the tree?
Hi NAME thanks for raising all these issues. There's an effort under way to give the draft an overhaul from an editorial standpoint. That should help with some of the issues around definitions and structuring/sequence of sections. Regarding : is just a function that's used in multiple places and the label changes depending on what kind of secret we're deriving. Regarding storage of authentication tags: I'm not sure what you mean by "store" here? This sounds like an implementation specific question that the draft won't be able to answer. Regarding two ratchets per leaf node: I assume you mean that from a leaf secret we derive a node secret and a path secret. This is to ensure that keys are cryptographically separate, such that they can be used by different cryptographic primitives. Cryptographic assumptions on primitives such as KDFs, authenticated encryption, etc usually assume that the key is only used with that primitive. As a consequence, proving the security of the protocol would likely require non-standard assumptions if one were not to separate keys properly. Regarding truncation: The sentence is meant to express that, starting from the rightmost leaf, leaves are removed until the first non-blank leaf is reached. Regarding resumptions and ExternalInits: Good catch! That should be added to the section on ExternalInit. Recovery through resumption secrets: When creating a group, it can be linked to an existing group through the use of resumption secrets. Linking a new group to an existing group means that the creator follows the normal group creation process, i.e. creating a group and adding other members, sending Welcome messages, etc. However, when adding the new members, the group creator also injects a PSK derived from the resumption secret (from the existing group) into the key schedule. Thus, as per the "normal" group creation process, no other shared secrets are needed, excpet the PSK derived from the resumption secret for the step where the members are added. Regarding you most recent example: If I understand the scenario correctly, I believe you are not computing the resolution properly. The node sending the update would encrypt the path secret of node 3 to the resolution of the blank node. The resolution of a blank node is computed by taking the resolution of its two children, which in this case are both C and D. I hope that answered some of your questions. If you have questions regarding the draft in general, the mailing list is usually a better place to get answers. Also, if you're working on an implementation, there's a Wire group for discussions regarding implementation issues and interop between the individual implementations. See for the links. We're always happy to see new implementations!
By "two ratchets", I was referring to the secrets derived at the leaves of the secret tree... i.e. the final values computed by . There's one using a label of "application" and one using a label of "handshake". The former is ratcheted for application messages, and the latter for handshake messages. In the diagram I referenced above, the label switches to "secret"... probably from an earlier iteration of the doc. In any case, I don't see a reason to have two secrets here. It's more to maintain for little benefit. Simply shifting leaves and then truncating the right side of the tree is sufficient to properly remove any arbitrary leaf from the tree? I guess maybe that works with the resolution computation you described, but that could like unmerge half the leaves between the departing index and the end. For the AES-256-GCM authentication tag, for the library in URL, the tag is retrieved with a separate call after the cipher is finalized (), so that the ciphertext and the tag are two pieces of information that need to get formatted into a packet and transmitted. I understand that this is just one algorithm and others may only have the ciphertext. But for the ciphersuites that employ AES-256-GCM, two implementations might format the packets differently and be inoperable with each other. ..or there's already an agreed upon formatting that I don't know about. Moreover, the length of the tag is a configurable param for the algorithm, which should be specified somewhere. I get it now that recovery is just group creation using the same group ID with a resumption secret thrown in. I kind of like it being an External Init with the resumption secret thrown in. One message instead of N messages. Mailing lists are terrible at organizing information (not that I'm doing any better putting all my topics in one Issue).
Hi NAME , finally getting around to addressing these comments. Sorry it took a bit! Notes from a first read-through (before looking at the exchange with NAME Terminology between Ratchet Tree Evolution, Group Creation, Key Schedule - I think this has been sorted out by some more recent changes. Definition of - This doesn't go in {{ratchet-tree-evolution}}, it is defined in the commit generation / handling sections "secret" / "handshake" / "application" - Yes, this is intentional. The first derivation splits the application and handshake key chains, then both evolve via "secret" derivation GCM authentication tag - We assume the RFC 5116 AEAD interface, which has a unitary ciphertext, not a separate ciphertext+tag. Added a note to clarify. Group creation and external init parts each have discussions in two parts - Not immediately clear how to address this; will consider in a broader review. Two ratchets per leaf node - Assuming you're talking about the vs. distinction, this is to assure that each secret is only used with one algortihm. I have added a note to clarify. Easier to understand resolution as depth-first search - Added this to the description of resolution. "Truncate the tree..." - Yep, missing part of the sentence. Reworded. Resumption secret & ExternalInit - There's no connection between ExternalInit and resumption secrets (just ), and in any case, the only epoch for which an ExternalInit can be constructed is the current one. Otherwise, you're forking history. You're correct that the resumption secret is not sufficient to join a group, and it's not meant to be. It is only proof of prior involvement with the group. For members A, C, D, ... - Your representation of the secret knowledge here isn't quite right. C and D wouldn't know p[1], since it's not on their direct path. In your hypothetical, if A or B did an operation, they would encrypt to the resolution of node 5, that is to both C and D. This diagram seems useful for building intuition, though, so I've added something like it to the ratchet tree section. Notes on responses to NAME The separate application and handshake ratchet to ensure that application and handshake messages don't fate-share -- if the application keys are compromised, that doesn't compromise the handshake keys. While this might not matter much in practice, I believe it helps with the security analysis. Truncation is not how members are removed from the tree. That's done by blanking a member's leaf and parents. Truncation is just garbage collection. If you have a 1000-member group where leaf 1 is blank (starting at zero), and the member at leaf 2 removes members at leaves 3-1000, then you'll end up with a tree with three leaves (member A, blank, member B), and truncation will clear out the now-blank leaves 3-1000 and all their parents. Yeah, there's unfortunate divergence in AES-GCM interfaces. The good news is that even if an implementation produces a different layout, as long as you can find the tag, you can rearrange things to match the desired layout here (ciphertext tag).
The top of Sec. 5 has exactly one sentence before diving into tree terminology. Please explain at a high level what is the motivation for this structure and maybe how it fits into the rest of the protocol.
My 2 cents: Abstractly, a distributed cryptographic state (like the ratchet tree) consists of a set of secrets. Each user j knows some subset S(j) of those secrets. More generally a set of users U collectively knows secrets S(U). To get Post Compromise Security for the distributed state we need a way for each user j to re-sample all secrets in S(j) and distribute such that the following is true. Suppose an adversary knows secrets S(U) in the old crypto state for some set of users U. Then in the new state, after witnessing the distribution phase on the wire, the adversary only knows the secrets in S(U{i}). For example: Suppose I steal your secrets (i.e. you are user j and now i know S(j)). Now you re-sample & distribute. As a result I now know S(emptyset) = nothing at all. The session is secure again. Suppose I steal the keys of users 2, 4 and 7. So i know S({2,4,7}). Then after 7 re-samples & distributes I only know S({2,4}). Once 2 and 4 also re-sample and distribute I know nothing and the session is secure again. In a nutshell, the ratchet tree in MLS gives us a way to efficiently do this re-sampling & distribution for commitsecrets repeatedly, non-interactively and efficiently. That is by sending out a single, reasonably small packet. Of course, as the ratchet tree adds more secrets to MLS distributed state we then have to be able to re-sample & distribute those as well which the ratchet tree lets us do. But at the end of the day, its all about distributing new commitsecrets.
LGTM. Thanks!
NAME - I put my own spin on this in . Let me know if that looks good to you!
NAME Absolutely. Thank you!

Revised text:
5. The protocol uses "ratchet trees" for deriving shared secrets among a  <ins> group of clients.  A ratchet tree is an arrangement of secrets and key pairs among the members of a group in a way that allows for secrets to be efficiently updated to reflect changes in the group. The unique power of a ratchet tree is that it allows a group to efficiently remove a member, because it allows a group member to efficiently encrypt new entropy to a subset of the group.  A ratchet tree assigns shared keys to subgroups of the overall group, so that, for example, encrypting to all but one member of the group requires only log(N) encryptions, instead of the N-1 encryptions that would be needed to encrypt to each participant individually (where N is the number of members in the group). This remove operation allows MLS to efficiently achieve post- compromise security.  In an Update proposal or a full Commit message, an old, possibly compromised representation of a member is effeciently removed from the group and replaced with a freshly generated instance. </ins> 5.1. A node in the tree may also be _blank_, indicating that no value is present at that node.  The _resolution_ of a node is an ordered list of non-blank nodes that collectively cover all non-blank descendants  <ins> of the node.  The resolution of a node is effectively a depth-first, left-first enumeration of the nearest non-blank nodes below the node: </ins> The resolution of a non-blank node comprises the node itself, followed by its list of unmerged leaves, if any "merged" as they receive the private keys for nodes, as described in ratchet-tree-evolution. <ins> For example, consider a four-member group (A, B, C, D) where the node above the right two members is blank.  (This is what it would look like if A created a group with B, C, and D.)  Then the public state of the tree and the views of the private keys of the tree held by each participant would be as follows, where "_" represents a blank node, "?" represents an unknown private key, and "pk(X)" represents the public key corresponding to the private key "X": Note how the tree invariant applies: Each member knows only their own leaf, and the private key AB is known only to A and B. </ins> 5.4. A member of an MLS group advances the key schedule to provide forward secret is used to derive a new secret value for the corresponding node, from which the node's key pair is derived. <ins> The node secret is derived as a temporary intermediate secret so that each secret is only used with one algorithm: The path secret is used as an input to DeriveSecret and the node secret is used as an input to DeriveKeyPair. </ins> For example, suppose there is a group with four members, with C an unmerged leaf at node 5: MLS uses HPKE for public-key encryption I-D.irtf-cfrg-hpke.  The "DeriveKeyPair" function associated to the KEM for the ciphersuite  <ins> maps octet strings to HPKE key pairs.  As in HPKE, MLS assumes that an AEAD algorithm produces a single ciphertext output from AEAD encryption (aligning with RFC5116), as opposed to a separate ciphertext and tag. </ins> Ciphersuites are represented with the CipherSuite type.  HPKE public keys are opaque values in a format defined by the underlying protocol Blank the intermediate nodes along the path from "removed_index" to the root  <ins> Truncate the tree by removing leaves from the right side of the tree until the rightmost leaf node is not blank. </ins> 11.1.4.