cryspen / scalable-mls-id

Other
0 stars 0 forks source link

LightCommit is problematic #6

Open bifurcation opened 2 months ago

bifurcation commented 2 months ago

The current LightCommit struct has some drawbacks. It seems simple on the surface because it's just a GroupInfo, but:

It seems to me that a better approach would be something like the following:

// OPTION B
struct LightCommit {
  GroupInfo group_info; // with tree_info extension relative to old tree hash
  TreeSlice recipient_membership_proof; // relative to the new tree hash
  EncryptedPathSecret encrypted_path_secret;
  PreSharedKeyID psks<V>;
}

This re-uses the GroupInfo with tree_info scheme (including the current/prior epoch weirdness), but moves the other information outside the signed envelope so that the DS can add it. The information is ultimately confirmed by the confirmation_tag in the GroupInfo, so it should be safe for the DS to add.

Option B is still a little unfortunate because it requires a committer to send both a GroupInfo and a Commit. This could be challenging for incremental deployment in a setting where committers aren't already sending GroupInfo alongside Commit, since it would require a behavior change at the committer as well as the light client. Another option that avoids that drawback would be something like:

// OPTION C
struct AnnotatedCommit {
  MLSMessage commit;
  TreeSlice sender_membership_proof; // relative to the old tree hash
  TreeSlice recipient_membership_proof; // relative to the new tree hash
  uint32 resolution_index;
  PreSharedKeyID psks<V>;
  Extension extensions<V>;
};

This can be generated by the DS based only on a Commit, and it avoids the tree_info old/new epoch weirdness. It also gets an extensions field in case of GroupContextExtensions proposals. (The confirmed_transcript_hash can be computed as usual.) The light client locates its HPKECiphertext in the UpdatePath by finding the first / lowest-level overlap with the direct path in its membership proof, then using the resolution_index to select from the individual encryptions. Obviously this is no longer really "light", though, because it carries the whole Commit, which can get heavy.

It seems like either B or C would be an update for the current state. It might be worth defining both, since they can cleanly coexist, and address different use cases.

bifurcation commented 2 months ago

FWIW, I have gotten the following flavor of AnnotatedCommit working in MLSpp:

struct AnnotatedCommit {
  MLSMessage commit_message;

  bytes tree_hash_after;
  TreeSlice sender_membership_proof_before;
  TreeSlice sender_membership_proof_after;
  TreeSlice receiver_membership_proof_after;

  optional<uint32_t> resolution_index;
};

Working in the sense of:

The DS logic to figure out which node in a Commit belongs to a given receiver is slightly non-trivial, but not terrible. It mostly worked on the first try, except for one bug that didn't show up until pretty far into the random-commits test vector.

All in all, this seems like a worthwhile thing to write up, at least as a transitional measure from a domain where clients don't produce GroupInfo already. (Note that it's possible to support LightCommit and AnnotatedCommit at the same time; the state in a light client is the same.) I'll work on some text.

The above structure might not be minimal. Or might not be secure! (But it seems OK?) Suggestions for improvement welcome. I already stripped out the extensions and psks fields, because you can get those from proposals.