Change:
One argument for the other option (i.e. force the root to be in the filtered updatepath): it gives a parent-hash chain from the comitting leaf to up to the root, hence the whole tree is bound in the leaf signature (assuming ). It ensures you can't modify the empty subtree. I don't think that's a huge deal, because you can always do modifications like this: given a tree T1, you can create tree T2 and a new root R like this (with the parent-hash link of R coming from T2): But it's worth noting that this change is not purely a TreeKEM change.
Interim 2022-06-02 As NAME notes in his comments, tree malleability is not worth blocking this for because you won't block the tree-extension attack anyway NAME notes the exception case where the UpdatePath has no nodes in it NAME suggests we should just forbid that case NAME will file a new PR to forbid that case
As I was pondering pathological cases related to , it occurred to me that we already have a slightly odd situation that can arise as a result of the suppression of redundant nodes. When a Commit has an UpdatePath, the is defined as follows: However, there are situations where the root node is not assigned a value, namely when the left half of the tree is blank. For example, suppose A creates a group with B, C, D: Suppose that then C removes A and B, leaving C and D as the only leaves in the tree. After removing A and B, the tree on which C computes an UpdatePath is as follows: C's direct path is (Z, Y), but it's filtered direct path is just (Z) because the copath subtree of Y is all blank. So C will not generate a pathsecret for Y, which means that the commit secret is not really defined. It seems like there are two paths to fix this: Keep the current definition of and require that a path secret always be generated for the root node Presumably the root node path secret would be generated directly from the path secret in the UpdatePath This would be simple to implement by just forcing the root node to be in the filtered direct path Keep the current path secret generation and specify that the is derived from the last path secret in the UpdatePath In the above example, the last path secret from the path secret for Z I lean slightly toward (2) because it makes the computation the same for two neighbors regardless of where they are in the tree. It seems like the two options primarily differ in whether there are one or two invocations of the key derivation.
Interim 2022-05-26: NAME supports doing "end of UpdatePath plus one" NAME to write up a PR
First, both fixes are secure. I lean towards "end of path plus one", because it matches better my mental model: a) if any node (including root) has a child with a blank subtree, then it's blank, b) we generate from the last secret generated by the committer. NAME while you're at it, you could also address the empty-UpdatePath ambiguity: If a member is alone in the group and sends a commit that doesn't add anyone, his UpdatePath is empty and he doesn't know how to derive . This can happen even without filtered paths, if the tree has exactly 1 node. There are 2 solutions: Pick a random secret Disallow such commits Regarding 2, does anyone know any reason we may want such commits?

Discussion:
Generate path secrets for the parent nodes along the sender's filtered direct path, as described in synchronizing-views-of- the-tree.  Define "commit_secret" as the value <del> "path_secret[n+1]" derived from the "path_secret[n]" value assigned to the root node. </del> <ins> "path_secret[n+1]" derived from the last path secret value ("path_secret[n]") derived for the UpdatePath. </ins> Update the new ratchet tree by setting the parent nodes on the sender's filtered direct path based on the path secrets.

"leaf_node" at the committer's leaf. Define "commit_secret" as the value "path_secret[n+1]" derived <del> from the "path_secret[n]" value assigned to the root node. </del> <ins> from the last path secret value ("path_secret[n]") derived for the UpdatePath. </ins> If the "path" value is not populated: Define "commit_secret" as the all-zero vector of length "KDF.Nh" (the same length as a