Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Replace proposal #174

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft

Add a Replace proposal #174

wants to merge 26 commits into from

Conversation

bifurcation
Copy link
Contributor

Issues:

Resolves #170

Description of changes:

This PR implements a Replace proposal long the lines discussed in #170 and draft-barnes-mls-replace. Changes are gated behind a feature flag replace_proposal, as discussed in #171.

Call-outs:

There are a few questions around error codes highlighted with XXX(RLB) in the code.

The current code does not reflect support for the Replace proposal in Capabilities when this feature is enabled, and probably should to be specification-compliant. Somewhat surprisingly, this does not cause tests to fail. I suspect there's a general bug to fix in that there doesn't seem to be any check that a proposal is supported by the group before it is applied.

Testing:

In general, the testing strategy is broadly parallel to testing of Update, since this new proposal type is closely related:

  • Tests that the commit builder properly includes Replace proposals in src/group/commit.rs
  • Tests of overall functionality in src/group/mod.rs
  • Tests that proposal list rules are applied in src/group/proposal_cache.rs

As a small drive-by, I also added tests that duplicate Updates are correctly filtered / detected, and the corresponding code to implement this policy.

I think these tests are complete and in the right places, but my familiarity with this code base is pretty rudimentary.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT license.

Copy link
Contributor

@mulmarta mulmarta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @bifurcation !

I'm still reviewing, but I added some initial comments I had when looking.

mls-rs-core/src/group/proposal_type.rs Outdated Show resolved Hide resolved
mls-rs-crypto-cryptokit/src/lib.rs Outdated Show resolved Hide resolved
Comment on lines +203 to +207
pub fn replace_member(
mut self,
to_replace: u32,
leaf_node: LeafNode,
) -> Result<Self, MlsError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a public interface to obtain the LeafNode? Maybe it would be easier to do replace_member(mut self, to_replace: u32, proposal: UpdateProposal) or even replace_member(mut self, proposal: MlsMessage) (message contains index) ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, to date we have made LeafNode private, maybe it should stay private?

mls-rs/src/group/mod.rs Outdated Show resolved Hide resolved
mls-rs/src/group/proposal_cache.rs Show resolved Hide resolved
mls-rs/src/group/proposal_filter/filtering.rs Outdated Show resolved Hide resolved
mls-rs/src/group/proposal_filter/filtering.rs Outdated Show resolved Hide resolved
mls-rs/src/group/snapshot.rs Outdated Show resolved Hide resolved
mls-rs/src/group/mod.rs Outdated Show resolved Hide resolved
Comment on lines +977 to +982
/// Abandon any cached state corresponding to a leaf node
#[cfg(feature = "replace_proposal")]
#[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
pub async fn abandon_leaf_node(&mut self, leaf_node: &LeafNode) {
self.pending_updates.remove(&leaf_node.public_key);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it annoying for the application to track LeafNode's?

Can we make it automatic so that leaves with epoch <= current leaf epoch are deleted automatically since they can no longer be applied? Storing other leaves can't hurt security (since they haven't been applied) so this function isn't so crucial anymore.

Also, how about a function that deletes all cached leaves, or all leaves with not_before < given time T, or all leaves from epoch < given epoch E?

Comment on lines +885 to +889
#[cfg(not(feature = "replace_proposal"))]
let extension_types = Default::default();

#[cfg(feature = "replace_proposal")]
let extension_types = vec![ExtensionType::LEAF_NODE_EPOCH];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious if this should be default or not just because the feature is on? I think I view the feature more as "you can possibly do this" vs "you definitely want to do this"

Comment on lines +203 to +207
pub fn replace_member(
mut self,
to_replace: u32,
leaf_node: LeafNode,
) -> Result<Self, MlsError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, to date we have made LeafNode private, maybe it should stay private?

@@ -265,8 +280,7 @@ where
private_tree: TreeKemPrivate,
key_schedule: KeySchedule,
#[cfg(feature = "by_ref_proposal")]
pending_updates:
crate::map::SmallMap<HpkePublicKey, (HpkeSecretKey, Option<SignatureSecretKey>)>, // Hash of leaf node hpke public key to secret key
pending_updates: SmallMap<HpkePublicKey, PendingUpdate>, // Hash of leaf node hpke public key to secret key
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mulmarta I think that we persist this data to disk as part of the group state itself? If so making this change would break loading group states from before this version. We can probably just try to deserialize the new format followed by the old format somehow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a Replace proposal
3 participants