Change:
Right now, we blank out leaf nodes when we remove their holders, but we never reduce the size of hte tree or repopulate interior blanks with new members. This PR adds those functions: Reduce the size of the tree and the roster when you remove from the right edge Add an field to the message, to enable new members to be added to blank slots in the tree, not just at the right edge. In addition to performing "garbage collection", this change should make it easier to do a state resync -- just remove the desync'ed endpoint and add them back in the same spot.
NAME Do you think this is ready to merge? say it's OK as long as we can convince ourselves that truncation preserves the tree invariant. Proof sketch: The tree invariant is a universal statement over nodes in the tree and members in the group: ! Since subtrees are just subsets of the set of nodes in the tree, if the tree invariant holds for a given tree, then it also holds for any subtree of that tree. So since truncation just moves from a tree to a subtree, the invariant continues to hold.
Currently, the tree only ever grows: When you add someone, you have to add them at the right edge, even if there are blank leaves When you remove someone, the tree never shrinks We should enable reclaiming of blank leaves and automatically reduce the size of the tree to the minimum necessary size.
After discussion at 2019-01 interim: Agreement that this seems OK as long as we can verify that the tree invariant holds when you truncate the tree.

Discussion:
they need to update their GroupState with information about the new member: <ins> The "index" field indicates where in the tree the new member should be added.  The new member can be added at an existing, blank leaf node, or at the right edge of the tree.  In any case, the "index" value MUST satisfy "0 <= index <= n", where "n" is the size of the group.  The case "index = n" indicates an add at the right edge of the tree).  If "index < n" and the leaf node at position "index" is not blank, then the recipient MUST reject the Add as malformed. </ins> A group member generates this message by requesting a UserInitKey from the directory for the user to be added, and encoding it into an Add message.

An existing member receiving a Add message first verifies the signature on the message, then updates its state as follows: <del> Increment the size of the group </del> <ins> If the "index" value is equal to the size of the group, increment the size of the group, and extend the tree and roster accordingly </ins> Verify the signature on the included UserInitKey; if the signature verification fails, abort <del> Append an entry to the roster containing the credential in the </del> <ins> Set the roster entry at position "index" to the credential in the </ins> included UserInitKey <del> Update the ratchet tree by adding a new leaf node for the new member, containing the public key from the UserInitKey in the Add corresponding to the ciphersuite in use </del> Update the ratchet tree by setting to blank all nodes in the <del> direct path of the new node, except for the leaf (which remains set to the new member's public key) </del> <ins> direct path of the new node Set the leaf node in the tree at position "index" to a new node containing the public key from the UserInitKey in the Add corresponding to the ciphersuite in use </ins> The update secret resulting from this change is an all-zero octet string of length Hash.length.

Update the ratchet tree by replacing nodes in the direct path from the removed leaf using the information in the Remove message <ins> Reduce the size of the roster and the tree until the rightmost element roster element and leaf node are non-null </ins> Update the ratchet tree by setting to blank all nodes in the direct path of the removed leaf