Documentation Index
Fetch the complete documentation index at: https://mintlify.com/openmls/openmls/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Update your own key material in the group. This operation creates a Commit that includes a path with new encryption keys and can optionally update your credential, capabilities, and extensions.
Self Update
Basic Update
Update key material with default parameters:
use openmls::prelude::*;
let leaf_node_params = LeafNodeParameters::default();
let bundle = alice_group.self_update(
provider,
&signer,
leaf_node_params,
)?;
let commit = bundle.commit();
let welcome = bundle.welcome(); // Some if there were pending Adds
let group_info = bundle.group_info();
// Send commit to group
alice_group.merge_pending_commit(provider)?;
Update with New Parameters
Update credential, capabilities, or extensions:
let new_capabilities = Capabilities::builder()
.versions(vec![ProtocolVersion::Mls10])
.ciphersuites(vec![ciphersuite])
.extensions(vec![ExtensionType::ApplicationId])
.build();
let new_extensions = Extensions::single(
Extension::ApplicationId(ApplicationIdExtension::new(b"my-app-id"))
);
let leaf_node_params = LeafNodeParameters::builder()
.with_capabilities(new_capabilities)
.with_extensions(new_extensions)
.build();
let bundle = alice_group.self_update(
provider,
&signer,
leaf_node_params,
)?;
alice_group.merge_pending_commit(provider)?;
Update Signature Key
Update your signature public key (requires new signer):
// Generate new signature key pair
let new_signature_keypair = SignatureKeyPair::new(
ciphersuite.signature_algorithm()
)?;
new_signature_keypair.store(provider.storage())?;
let new_signer = NewSignerBundle {
signer: &new_signature_keypair,
new_public_key: new_signature_keypair.public().into(),
};
let leaf_node_params = LeafNodeParameters::builder()
.with_signature_public_key(new_signature_keypair.public().into())
.build();
let bundle = alice_group.self_update_with_new_signer(
provider,
&old_signer,
new_signer,
leaf_node_params,
)?;
alice_group.merge_pending_commit(provider)?;
Method Signatures
self_update
OpenMLS provider for crypto and storage
Your current signature key
leaf_node_parameters
LeafNodeParameters
required
New parameters for your leaf node
Returns: Result<CommitMessageBundle, SelfUpdateError>
The bundle contains:
- Commit message
- Optional Welcome (if there were pending Add proposals)
- Optional GroupInfo
Location: openmls/src/group/mls_group/updates.rs:23
self_update_with_new_signer
Update including signature public key change.
OpenMLS provider for crypto and storage
Your current signature key
New signature key and public key
leaf_node_parameters
LeafNodeParameters
required
New parameters (must include new signature public key)
Returns: Result<CommitMessageBundle, SelfUpdateError>
Location: openmls/src/group/mls_group/updates.rs:62
propose_self_update
Create an Update proposal without committing.
OpenMLS provider for crypto and storage
leaf_node_parameters
LeafNodeParameters
required
New parameters for your leaf node
Returns: Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError>
Location: openmls/src/group/mls_group/updates.rs:148
Leaf Node Parameters
Configure what to update in your leaf node:
let params = LeafNodeParameters::builder()
.with_capabilities(capabilities)
.with_extensions(extensions)
.with_signature_public_key(public_key) // Only with new_signer
.build();
Update supported protocol versions, ciphersuites, extensions, and proposals
Update leaf node extensions (e.g., ApplicationId)
with_signature_public_key
Update signature public key (requires self_update_with_new_signer)
Complete Examples
Simple Key Rotation
Create update parameters
let leaf_node_params = LeafNodeParameters::default();
Perform update
let bundle = alice_group.self_update(
provider,
&alice_signer,
leaf_node_params,
)?;
Send and merge
let commit = bundle.commit();
delivery_service.send_to_group(alice_group.group_id(), commit)?;
alice_group.merge_pending_commit(provider)?;
Update Credential
Create new credential
let new_credential = BasicCredential::new(
b"alice@new-domain.example".to_vec()
)?;
let new_credential_with_key = CredentialWithKey {
credential: new_credential.into(),
signature_key: current_signature_public_key.into(),
};
Build leaf parameters
// Note: Updating credential requires more complex setup
// You need to update both the credential and ensure
// the signature key matches
let leaf_node_params = LeafNodeParameters::builder()
// Set other parameters
.build();
Update and merge
let bundle = alice_group.self_update(
provider,
&alice_signer,
leaf_node_params,
)?;
alice_group.merge_pending_commit(provider)?;
Propose Update (Two-Step)
Create update proposal
let (proposal_msg, proposal_ref) = alice_group.propose_self_update(
provider,
&alice_signer,
leaf_node_params,
)?;
Send proposal
delivery_service.send_to_group(
alice_group.group_id(),
proposal_msg,
)?;
Commit later
// Someone (possibly you) commits the proposal
let (commit, welcome, group_info) = alice_group
.commit_to_pending_proposals(provider, &alice_signer)?;
alice_group.merge_pending_commit(provider)?;
Processing Updates
Other members process your update:
// Bob receives and processes Alice's update
let processed = bob_group.process_message(provider, commit_msg)?;
if let ProcessedMessageContent::StagedCommitMessage(staged_commit) =
processed.into_content()
{
// Check for update proposals
for update in staged_commit.update_proposals() {
println!("Member {} updated their leaf", update.sender());
}
// Merge the commit
bob_group.merge_staged_commit(provider, *staged_commit)?;
}
Error Handling
match alice_group.self_update(provider, &signer, params) {
Ok(bundle) => {
// Success
}
Err(SelfUpdateError::GroupStateError(state_error)) => {
match state_error {
MlsGroupStateError::PendingCommit => {
// Must merge or clear pending commit first
}
MlsGroupStateError::UseAfterEviction => {
// Can't update after being removed
}
}
}
Err(SelfUpdateError::CreateCommitError(commit_error)) => {
// Failed to create commit
}
Err(e) => eprintln!("Error updating: {}", e),
}
Advanced Usage
Using CommitBuilder
let bundle = alice_group
.commit_builder()
.leaf_node_parameters(leaf_node_params)
.consume_proposal_store(true) // Include pending proposals
.load_psks(provider.storage())?
.build(provider.rand(), provider.crypto(), &signer, |_| true)?
.stage_commit(provider)?;
let commit = bundle.commit();
alice_group.merge_pending_commit(provider)?;
Update with Other Proposals
// Update yourself and add members in one commit
let bundle = alice_group
.commit_builder()
.leaf_node_parameters(leaf_node_params)
.propose_adds(key_packages.iter().cloned())
.load_psks(provider.storage())?
.build(provider.rand(), provider.crypto(), &signer, |_| true)?
.stage_commit(provider)?;
Important Notes
Signature Key Update: When updating your signature public key, you MUST use self_update_with_new_signer() and the new public key in LeafNodeParameters must match the NewSignerBundle.
Automatic Path: self_update() always includes a path in the commit, updating your encryption keys even if you only change other parameters.
Extension Support: The updated leaf node must support all group context extensions. The update will fail if it doesn’t.
Pending Proposals: self_update() consumes all pending proposals by default. Use CommitBuilder for more control.
When to Update
Update your key material when:
- Regular Rotation: Periodically for forward secrecy
- Credential Change: When your identity information changes
- Capabilities Change: When you want to support new features
- Key Compromise: If you suspect your keys are compromised
- Policy Requirement: When group policy requires updates
Next Steps