Subject: [MLS] RT array implementation motivation

From: Tijana Klimovic <[email-masked]>
Date: Wed, 19 May 2021 14:55:48 +0200

Hello,

I have only recently started to look into the MLS specification, and was
wondering why the ratchet tree (RT) structure is chosen to be implemented
with an array. From what I understand, the pointer-based tree where each
node would contain the following information:

        struct {
        Node* sibling;
        Node* parent;
        Node* left_child;
        Node* right_child;
        Optional<HPKEPublicEncKey> hpke_enc_pk;
        Optional<HPKESecretEncKey> hpke_enc_sk;
        Optional<Credential> credential;
        Optional<vector<byte>> parent_hash;
        Optional<vector<Node*>> unmerged_leaves;
        } Node

would be more efficient than an array w.r.t. all operations supported by
the RT.

Many thanks.
Tijana

---

From: Richard Barnes <[email-masked]>
Date: Wed, 19 May 2021 09:24:59 -0400

Hi Tijana,

The specification doesn't require that the tree be implemented in a given
way.  Implementations are free to arrange their memory however they like.
The array notation just gives us a simple way to assign each node in the
tree an index.

--Richard

On Wed, May 19, 2021 at 8:56 AM Tijana Klimovic <[email-masked]>
wrote:

> _______________________________________________
> MLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/mls
>

---

From: Raphael Robert <[email-masked]>
Date: Wed, 19 May 2021 15:25:40 +0200

Hi Tijana,

At the end of the day you can use whatever implementation works best of course. The array approach has a few benefits though:
 - it’s language agnostic, something that’s important for IETF
 - it gives you a serialisation format for free (quite practical for the ratchet tree extension)
 - it let’s you use references to nodes in the tree that are used in the Secret Tree to derive secrets for example
 - it makes it easy to add and remove nodes without having to change anything in neighbouring nodes

From a performance standpoint, using the tree math provided should also be reasonably fast. If you have some benchmarks to share that prove otherwise, it would be interesting to look into it.

Lastly, pointers can be great, but they can also be quite dangerous if implemented wrongly.

Hope this helps,

Raphael

> On 19. May 2021, at 14:55, Tijana Klimovic <[email-masked]> wrote:
> 
> Hello,
> 
> I have only recently started to look into the MLS specification, and was wondering why the ratchet tree (RT) structure is chosen to be implemented with an array. From what I understand, the pointer-based tree where each node would contain the following information: 
> 
>         struct {
>         Node* sibling;
>         Node* parent;
>         Node* left_child;
>         Node* right_child;
> would be more efficient than an array w.r.t. all operations supported by the RT. 
> 
> Many thanks.
> Tijana

---

From: Tijana Klimovic <[email-masked]>
Date: Wed, 19 May 2021 17:11:37 +0200

Hello,

Thank you for your answers to the question about RT. I do have some more
questions about the choice of framing if you don't mind me asking. I tried
to find answers to them in the group but didn't have much luck.

Namely, in the MLSPlaintext structure, you have the membership_tag included
that MACs everything above it in the MLSPlaintext structure with the
membership_key. I don't see how the framing is any less secure without it
being there, since the signature covers everything above itself, hence only
not including the two mac tags.

Furthermore, it's not clear to me which membership_key is used to construct
it in case of commit messages. I would think that it would be the
membership_key deduced from the GroupContext for the new epoch, after the
proposals and UpdatePath have been applied so that joiners can compute the
epoch_secret. Is this correct?

Lastly, I wanted to ask what is the purpose of having the parent_hash
extension?

As far as I understand, it only must be included in the leafKeyPackage of
the UpdatePath structure and it serves to bind the new HPKE public keys of
all nodes on the path from the leaf(committer) with the leafKeyPackage to
the root and the set of HPKE public keys to which PK's secret key was
encrypted. But the commit contains the confirmation_tag that confirms that
the members of the group have arrived at the same state of the group. So
the confirmation_tag would bind the same as the parent_hash and even more.

Many thanks.
Tijana

On Wed, 19 May 2021 at 15:25, Raphael Robert <[email-masked]> wrote:

> Hi Tijana,
>
> At the end of the day you can use whatever implementation works best of
> course. The array approach has a few benefits though:
>  - it let’s you use references to nodes in the tree that are used in the
> Secret Tree to derive secrets for example
> From a performance standpoint, using the tree math provided should also be
> reasonably fast. If you have some benchmarks to share that prove otherwise,
> it would be interesting to look into it.
>

---

From: Raphael Robert <[email-masked]>
Date: Thu, 20 May 2021 16:32:52 +0200

> Namely, in the MLSPlaintext structure, you have the membership_tag included that MACs everything above it in the MLSPlaintext structure with the membership_key. I don't see how the framing is any less secure without it being there, since the signature covers everything above itself, hence only not including the two mac tags. 

The signature only proves the signer is in possession of the private signature key. The membership_tag also proves that the member has access to group secrets and that means that it is a member of the group from a cryptographic standpoint.

> Furthermore, it's not clear to me which membership_key is used to construct it in case of commit messages. I would think that it would be the membership_key deduced from the GroupContext for the new epoch, after the proposals and UpdatePath have been applied so that joiners can compute the epoch_secret. Is this correct?

The membership_key is an output of the key schedule as described in 8. It is used to compute the membership_tag as described in 9.1.

> Lastly, I wanted to ask what is the purpose of having the parent_hash extension? 
> 
> As far as I understand, it only must be included in the leafKeyPackage of the UpdatePath structure and it serves to bind the new HPKE public keys of all nodes on the path from the leaf(committer) with the leafKeyPackage to the root and the set of HPKE public keys to which PK's secret key was encrypted. But the commit contains the confirmation_tag that confirms that the members of the group have arrived at the same state of the group. So the confirmation_tag would bind the same as the parent_hash and even more.

The parent_hash is intended to be checked by new joiners. This way new joiners can come to the conclusion that existing members agreed on (some of) the public tree in the past. New joiners cannot derive that from the confirmation_tag when they process a Welcome message, because they don’t have all of the past transcript.

Raphael

> 
> Many thanks.
> Tijana
> 
> On Wed, 19 May 2021 at 15:25, Raphael Robert <[email-masked] <mailto:[email-masked]>> wrote:
> Hi Tijana,
> 
> > On 19. May 2021, at 14:55, Tijana Klimovic <[email-masked] <mailto:[email-masked]>> wrote:
> > 
> > Hello,
> > 
> > [email-masked] <mailto:[email-masked]>
> > https://www.ietf.org/mailman/listinfo/mls <https://www.ietf.org/mailman/listinfo/mls>
>