Skip to main content

CommitBuilder

Struct CommitBuilder 

Source
pub struct CommitBuilder<'a, T, G: BorrowMut<MlsGroup> = &'a mut MlsGroup> { /* private fields */ }
Available on 32-bit or 64-bit only.
Expand description

The CommitBuilder is used to easily and dynamically build commit messages. It operates in a series of stages:

The Initial stage is used to populate the builder with proposals and other data using method calls on the builder that let the builder stay in the same stage.

The next stage is LoadedPsks, and it signifies the stage after the builder loaded the the pre-shared keys for the PreSharedKey proposals in this commit.

Then comes the Complete stage, which denotes that all data has been validated. From this stage, the commit can be staged in the group, and the outgoing messages returned.

For example, to create a commit to a new Add proposal with a KeyPackage key_package_to_add that does not commit to the proposals in the proposal store, one could build the commit as follows:

let message_bundle: CommitMessageBundle = mls_group
  .commit_builder()
  .consume_proposal_store(false)
  .add_proposal(key_package_to_add)
  .load_psks(provider.storage())?
  .build(provider.rand(), provider.crypto(), signer, app_policy_proposals)?
  .stage_commit(provider)?;

let commit = message_bundle.commit();
let welcome = message_bundle.welcome().expect("expected a welcome since there was an add");
let group_info = message_bundle.welcome().expect("expected a group info since there was an add");

In this example signer is a reference to a [Signer] and app_policy_proposals is the application-defined policy for which proposals to accept, implemented by an FnMut(&QueuedProposal) -> bool.

See the book for another example.

Implementations§

Source§

impl<'a> CommitBuilder<'a, Initial, MlsGroup>

Source

pub fn add_proposal(self, proposal: Proposal) -> Self

Adds a proposal to the proposals to be committed by value. To add multiple proposals, use Self::add_proposals.

Only proposal types that are allowed by value in an external commit (such as PreSharedKey, Remove, or AppEphemeral) pass validation when the commit is built. Other types cause build to fail with ExternalCommitValidationError::InvalidInlineProposals.

Source

pub fn add_proposals( self, proposals: impl IntoIterator<Item = Proposal>, ) -> Self

Adds the proposals in the iterator to the proposals to be committed by value. See Self::add_proposal for the proposal types allowed in an external commit.

Source

pub fn add_psk_proposal(self, proposal: PreSharedKeyProposal) -> Self

Adds a PreSharedKeyProposal to the proposals to be committed.

Source

pub fn add_psk_proposals( self, proposals: impl IntoIterator<Item = PreSharedKeyProposal>, ) -> Self

Adds the PreSharedKeyProposal in the iterator to the proposals to be committed.

Source

pub fn add_app_data_update_proposal( self, proposal: AppDataUpdateProposal, ) -> Self

Available on crate feature extensions-draft only.

Adds an AppDataUpdateProposal.

Source§

impl CommitBuilder<'_, Complete, MlsGroup>

Source

pub fn finalize<Provider: OpenMlsProvider>( self, provider: &Provider, ) -> Result<(MlsGroup, CommitMessageBundle), ExternalCommitBuilderFinalizeError<Provider::StorageError>>

Finalizes and returns the MlsGroup, as well as the CommitMessageBundle.

In contrast to the deprecated MlsGroup::join_by_external_commit there is no need to merge the pending commit.

Source§

impl<'a, T, G: BorrowMut<MlsGroup>> CommitBuilder<'a, T, G>

Source

pub fn vc_epoch_id(&self) -> Option<&EpochId>

Available on crate feature virtual-clients-draft only.

Returns the EpochId of the derivation epoch this commit acts from, or None if no virtual-clients material was loaded.

Source§

impl<'a> CommitBuilder<'a, Initial, &mut MlsGroup>

Source

pub fn consume_proposal_store(self, consume_proposal_store: bool) -> Self

Sets whether or not the proposals in the proposal store of the group should be included in the commit. Defaults to true.

Source

pub fn force_self_update(self, force_self_update: bool) -> Self

Sets whether or not the commit should force a self-update. Defaults to false.

Source

pub fn propose_adds( self, key_packages: impl IntoIterator<Item = KeyPackage>, ) -> Self

Adds an Add proposal to the provided KeyPackage to the list of proposals to be committed.

Source

pub fn propose_removals( self, removed: impl IntoIterator<Item = LeafNodeIndex>, ) -> Self

Adds a Remove proposal for the provided LeafNodeIndexes to the list of proposals to be committed.

Source

pub fn propose_group_context_extensions( self, extensions: Extensions<GroupContext>, ) -> Result<Self, CreateCommitError>

Adds a GroupContextExtensions proposal for the provided Extensions to the list of proposals to be committed.

Source

pub fn propose_psks( self, psk_ids: impl IntoIterator<Item = PreSharedKeyId>, ) -> Self

Adds a PreSharedKey proposal for the provided PreSharedKeyIds to the list of proposals to be committed.

Note that this should not be used for sub-group branching, as those PSKs are not allowed in regular proposals. Please use MlsGroupBuilder::branch instead.

Source

pub fn add_proposal(self, proposal: Proposal) -> Self

Adds a proposal to the proposals to be committed. To add multiple proposals, use Self::add_proposals.

Source

pub fn add_proposals( self, proposals: impl IntoIterator<Item = Proposal>, ) -> Self

Adds the proposals in the iterator to the proposals to be committed.

Source§

impl<'a, G: BorrowMut<MlsGroup>> CommitBuilder<'a, Initial, G>

Source

pub fn new(group: G) -> CommitBuilder<'a, Initial, G>

returns a new CommitBuilder for the given MlsGroup.

Source

pub fn leaf_node_parameters( self, leaf_node_parameters: LeafNodeParameters, ) -> Self

Sets the leaf node parameters for the new leaf node in a self-update. Implies that a self-update takes place.

Source

pub fn vc_emulation<Crypto: OpenMlsCrypto, Storage: StorageProvider>( self, crypto: &Crypto, storage: &Storage, emulation_group_id: &GroupId, ) -> Result<Self, CreateCommitError>

Available on crate feature virtual-clients-draft only.

Opt this commit into the virtual-clients-draft sender flow.

The commit uses the newest derivation epoch of the emulation group named by emulation_group_id, which is what the draft requires of every new virtual-client operation. The epoch is resolved from the emulation group’s current state, so a commit that itself asks for a new derivation epoch (see Self::derivation_epoch) still uses the epoch of its input state: the requested one only exists once that commit is merged.

This method loads the per-epoch operation secret tree and AEAD key from the storage provider, validates the leaf configuration (see the preconditions below), then advances the own LeafNode operation ratchet by one generation and immediately persists the advanced tree. build then:

  • derives the path secret and the new leaf’s encryption keypair from the allocated OperationSecret, so a sibling virtual client can rederive them on the receiver side, and
  • embeds an encrypted DerivationInfo blob under VC_COMPONENT_ID in the new leaf’s app_data_dictionary extension.

Because the ratchet advance is persisted here, a builder that is discarded after this call burns a generation. The same happens when the DS rejects the commit. That is harmless because sibling ratchets skip over a burned generation, retaining the skipped generation secrets inside their copy of the operation secret tree.

The leaf configuration is validated against the leaf_node_parameters set on the builder so far, so call this after configuring the self-update leaf. The application must ensure the new leaf:

If those preconditions are not met this method fails with VirtualClientsError::AppDataDictionaryNotSupported or VirtualClientsError::VcComponentNotListed (wrapped in CreateCommitError::VirtualClientsError) before allocating a generation, so no operation secret is burned in that case.

Fails with VirtualClientsError::NoDerivationEpoch if the emulation group has no registered derivation epoch, and with VirtualClientsError::MissingDerivationEpochState or VirtualClientsError::MissingOperationTree if the resolved epoch’s state is gone. Neither the state nor the tree is instantiated on the fly, since that could diverge from a sibling virtual client’s already-advanced ratchets.

Implies that a self-update takes place: the commit will always have a path even if no other proposals are queued.

Source

pub fn vc_emulation_at_epoch<Crypto: OpenMlsCrypto, Storage: StorageProvider>( self, crypto: &Crypto, storage: &Storage, epoch_id: EpochId, ) -> Result<Self, CreateCommitError>

Available on crate feature virtual-clients-draft and (crate features test-utils) only.

Test-only variant of Self::vc_emulation that commits from the named derivation epoch instead of the emulation group’s newest one.

Using an epoch other than the newest one violates the draft, which requires every new virtual-client operation to use the newest derivation epoch of the acting client’s current emulation-group state. It exists to construct scenarios that an application must not produce, such as a sibling that acts on a stale emulation-group state.

Source

pub fn derivation_epoch(self, derivation_epoch: bool) -> Self

Available on crate feature virtual-clients-draft only.

Ask the emulation group to start a new derivation epoch with this commit.

When set, build makes sure the commit’s virtual-clients Safe AAD item carries a new_derivation_epoch action, creating the item if the application staged none. Every member of the emulation group then registers the epoch this commit moves the group into as a derivation epoch when the commit is merged, and subsequent virtual-client operations resolve to it.

This is the application’s cadence knob for post-compromise security of the virtual client’s secrets. Commits that change membership create a derivation epoch on their own, so they do not need this.

Like all actions, the marker applies relative to the commit’s input state. Operations that reference a derivation epoch keep using the newest derivation epoch of that input state, including operations carried by this very commit.

The group has to be configured as an emulation group and its GroupContext has to require Safe AAD framing. Otherwise build fails with CreateCommitError::NewDerivationEpochOutsideEmulationGroup or CreateCommitError::NewDerivationEpochWithoutSafeAad.

Source

pub fn load_psks<Storage: StorageProvider>( self, storage: &'a Storage, ) -> Result<CommitBuilder<'a, LoadedPsks, G>, CreateCommitError>

Loads the PSKs for the PskProposals marked for inclusion and moves on to the next phase.

Source§

impl<'a, G: BorrowMut<MlsGroup>> CommitBuilder<'a, LoadedPsks, G>

Source

pub fn create_group_info(self, create_group_info: bool) -> Self

Sets whether or not a GroupInfo should be created when the commit is staged. Defaults to the value of the MlsGroups MlsGroupJoinConfig.

Source

pub fn use_ratchet_tree_extension( self, use_ratchet_tree_extension: bool, ) -> Self

Sets whether the GroupInfo should contain the ratchet tree extension. If set to true, enables the GroupInfo to be created when the commit is staged.

Source

pub fn create_group_info_with_extensions( self, extensions: impl IntoIterator<Item = Extension>, ) -> Result<Self, InvalidExtensionError>

Add the provided Extensions to the GroupInfo.

Returns an error if a RatchetTreeExtension or ExternalPubExtension is added directly here.

Source

pub fn build<S: Signer>( self, rand: &impl OpenMlsRand, crypto: &impl OpenMlsCrypto, signer: &S, f: impl FnMut(&QueuedProposal) -> bool, ) -> Result<CommitBuilder<'a, Complete, G>, CreateCommitError>

Validates the inputs and builds the commit. The last argument f is a function that lets the caller filter the proposals that are considered for inclusion. This provides a way for the application to enforce custom policies in the creation of commits.

Source

pub fn build_with_new_signer<S: Signer>( self, rand: &impl OpenMlsRand, crypto: &impl OpenMlsCrypto, old_signer: &impl Signer, new_signer: NewSignerBundle<'_, S>, f: impl FnMut(&QueuedProposal) -> bool, ) -> Result<CommitBuilder<'a, Complete, G>, CreateCommitError>

Just like build, this function validates the inputs and builds the commit. The last argument f is a function that lets the caller filter the proposals that are considered for inclusion. This provides a way for the application to enforce custom policies in the creation of commits.

In contrast to build, this function can be used to create commits that rotate the own leaf node’s signature key. Supplying a new signer implies a self-update: the commit always contains an UpdatePath that installs the new signature key in the committer’s leaf, even if no proposal requires a path.

The Commit message itself is signed with old_signer, because receivers verify it against the committer’s pre-commit leaf. GroupInfo objects created for this commit are signed with the new signer, matching the post-commit leaf.

Returns an error if the new signer’s signature scheme does not match the group’s ciphersuite, or when used on an external commit. External commits take their credential and signer from the external commit builder.

Source

pub fn app_data_dictionary_updater(&self) -> AppDataDictionaryUpdater<'_>

Available on crate feature extensions-draft only.

Creates a new AppDataUpdates based on the current state of the AppDataDictionary of the group.

Source

pub fn with_app_data_dictionary_updates( &mut self, app_data_dictionary_updates: Option<AppDataUpdates>, )

Available on crate feature extensions-draft only.

Sets the AppDataUpdates that contain the changes made by the AppDataUpdate proposals

Source

pub fn app_data_update_proposals( &self, ) -> impl Iterator<Item = &AppDataUpdateProposal>

Available on crate feature extensions-draft only.

Returns an iterator over all AppDataUpdate proposals in the proposal store of the group

Source§

impl CommitBuilder<'_, Complete, &mut MlsGroup>

Source

pub fn stage_commit<Provider: OpenMlsProvider>( self, provider: &Provider, ) -> Result<CommitMessageBundle, CommitBuilderStageError<Provider::StorageError>>

Stages the commit and returns the protocol messages.

Source§

impl<'a> CommitBuilder<'a, ReAddExpectKeyPackages>

Source

pub fn complement_partition(&self) -> &[Member]

Available on crate feature fork-resolution only.

Returns the complement partition, i.e. the list of members that are not in our partition.

Source

pub fn provide_key_packages( self, new_key_packages: Vec<KeyPackage>, ) -> CommitBuilder<'a, Initial>

Available on crate feature fork-resolution only.

Takes the key packages needed to re-add the other members and returns the prepared CommitBuilder.

Trait Implementations§

Source§

impl<'a, T: Debug, G: Debug + BorrowMut<MlsGroup>> Debug for CommitBuilder<'a, T, G>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a, T, G> Freeze for CommitBuilder<'a, T, G>
where G: Freeze, T: Freeze,

§

impl<'a, T, G> RefUnwindSafe for CommitBuilder<'a, T, G>

§

impl<'a, T, G> Send for CommitBuilder<'a, T, G>
where G: Send, T: Send,

§

impl<'a, T, G> Sync for CommitBuilder<'a, T, G>
where G: Sync, T: Sync,

§

impl<'a, T, G> Unpin for CommitBuilder<'a, T, G>
where G: Unpin, T: Unpin,

§

impl<'a, T, G> UnsafeUnpin for CommitBuilder<'a, T, G>
where G: UnsafeUnpin, T: UnsafeUnpin,

§

impl<'a, T, G> UnwindSafe for CommitBuilder<'a, T, G>
where G: UnwindSafe, T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V