Skip to content

Commit

Permalink
feat: provide async storage interface [WPB-9772]
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonThormeyer committed Jun 24, 2024
1 parent 2f835f7 commit 35006f7
Show file tree
Hide file tree
Showing 24 changed files with 573 additions and 281 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ tls_codec = { version = "0.4.2-pre.1", features = [
"serde",
"mls",
], git = "https://github.com/rustcrypto/formats" }
maybe-async = "0.2.10"
async-trait = "0.1.80"
4 changes: 4 additions & 0 deletions openmls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ openmls_memory_storage = { path = "../memory_storage", features = [
openmls_test = { path = "../openmls_test", optional = true }
openmls_libcrux_crypto = { path = "../libcrux_crypto", optional = true }
once_cell = { version = "1.19.0", optional = true }
maybe-async = {workspace = true}
async-trait = { workspace = true, optional = true }
futures = { version = "0.3.30", optional = true }

[features]
default = ["backtrace"]
Expand All @@ -62,6 +65,7 @@ js = [
"dep:getrandom",
"dep:fluvio-wasm-timer",
] # enable js randomness source for provider
async = ["dep:async-trait", "openmls_traits/async", "dep:futures"]

[dev-dependencies]
backtrace = "0.3"
Expand Down
113 changes: 70 additions & 43 deletions openmls/src/group/core_group/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ pub(crate) struct CoreGroupBuilder {
max_past_epochs: usize,
}

#[cfg_attr(feature = "async", maybe_async::must_be_async)]
#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
impl CoreGroupBuilder {
/// Create a new [`CoreGroupBuilder`].
pub(crate) fn new(
Expand Down Expand Up @@ -266,7 +268,7 @@ impl CoreGroupBuilder {
///
/// This function performs cryptographic operations and there requires an
/// [`OpenMlsProvider`].
pub(crate) fn build<Provider: OpenMlsProvider>(
pub(crate) async fn build<Provider: OpenMlsProvider>(
self,
provider: &Provider,
signer: &impl Signer,
Expand Down Expand Up @@ -302,7 +304,7 @@ impl CoreGroupBuilder {

// Prepare the PskSecret
let psk_secret = {
let psks = load_psks(provider.storage(), &resumption_psk_store, &self.psk_ids)?;
let psks = load_psks(provider.storage(), &resumption_psk_store, &self.psk_ids).await?;

PskSecret::new(provider.crypto(), ciphersuite, psks)?
};
Expand Down Expand Up @@ -347,17 +349,21 @@ impl CoreGroupBuilder {
// Store the group state
group
.store(provider.storage())
.await
.map_err(CoreGroupBuildError::StorageError)?;

// Store the private key of the own leaf in the key store as an epoch keypair.
group
.store_epoch_keypairs(provider.storage(), &[leaf_keypair])
.await
.map_err(CoreGroupBuildError::StorageError)?;

Ok(group)
}
}

#[cfg_attr(feature = "async", maybe_async::must_be_async)]
#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
impl CoreGroup {
/// Get a builder for [`CoreGroup`].
pub(crate) fn builder(
Expand Down Expand Up @@ -488,7 +494,7 @@ impl CoreGroup {
}

// Create application message
pub(crate) fn create_application_message<Provider: OpenMlsProvider>(
pub(crate) async fn create_application_message<Provider: OpenMlsProvider>(
&mut self,
aad: &[u8],
msg: &[u8],
Expand All @@ -503,11 +509,11 @@ impl CoreGroup {
self.context(),
signer,
)?;
self.encrypt(public_message, padding_size, provider)
self.encrypt(public_message, padding_size, provider).await
}

// Encrypt an PublicMessage into an PrivateMessage
pub(crate) fn encrypt<Provider: OpenMlsProvider>(
pub(crate) async fn encrypt<Provider: OpenMlsProvider>(
&mut self,
public_message: AuthenticatedContent,
padding_size: usize,
Expand All @@ -524,6 +530,7 @@ impl CoreGroup {
provider
.storage()
.write_message_secrets(self.group_id(), &self.message_secrets_store)
.await
.map_err(MessageEncryptionError::StorageError)?;

Ok(msg)
Expand Down Expand Up @@ -726,33 +733,43 @@ impl CoreGroup {

/// Stores the [`CoreGroup`]. Called from methods creating a new group and mutating an
/// existing group, both inside [`CoreGroup`] and in [`MlsGroup`].
pub(super) fn store<Storage: StorageProvider>(
pub(super) async fn store<Storage: StorageProvider>(
&self,
storage: &Storage,
) -> Result<(), Storage::Error> {
let group_id = self.group_id();

self.public_group.store(storage)?;
storage.write_own_leaf_index(group_id, &self.own_leaf_index())?;
storage.write_group_epoch_secrets(group_id, &self.group_epoch_secrets)?;
storage.set_use_ratchet_tree_extension(group_id, self.use_ratchet_tree_extension)?;
storage.write_message_secrets(group_id, &self.message_secrets_store)?;
storage.write_resumption_psk_store(group_id, &self.resumption_psk_store)?;
self.public_group.store(storage).await?;
storage
.write_own_leaf_index(group_id, &self.own_leaf_index())
.await?;
storage
.write_group_epoch_secrets(group_id, &self.group_epoch_secrets)
.await?;
storage
.set_use_ratchet_tree_extension(group_id, self.use_ratchet_tree_extension)
.await?;
storage
.write_message_secrets(group_id, &self.message_secrets_store)
.await?;
storage
.write_resumption_psk_store(group_id, &self.resumption_psk_store)
.await?;

Ok(())
}

/// Loads a [`CoreGroup`]. Called in [`MlsGroup::load`].
pub(super) fn load<Storage: StorageProvider>(
pub(super) async fn load<Storage: StorageProvider>(
storage: &Storage,
group_id: &GroupId,
) -> Result<Option<Self>, Storage::Error> {
let public_group = PublicGroup::load(storage, group_id)?;
let group_epoch_secrets = storage.group_epoch_secrets(group_id)?;
let own_leaf_index = storage.own_leaf_index(group_id)?;
let use_ratchet_tree_extension = storage.use_ratchet_tree_extension(group_id)?;
let message_secrets_store = storage.message_secrets(group_id)?;
let resumption_psk_store = storage.resumption_psk_store(group_id)?;
let public_group = PublicGroup::load(storage, group_id).await?;
let group_epoch_secrets = storage.group_epoch_secrets(group_id).await?;
let own_leaf_index = storage.own_leaf_index(group_id).await?;
let use_ratchet_tree_extension = storage.use_ratchet_tree_extension(group_id).await?;
let message_secrets_store = storage.message_secrets(group_id).await?;
let resumption_psk_store = storage.resumption_psk_store(group_id).await?;

let build = || -> Option<Self> {
Some(Self {
Expand All @@ -768,16 +785,20 @@ impl CoreGroup {
Ok(build())
}

pub(super) fn delete<Storage: StorageProvider>(
pub(super) async fn delete<Storage: StorageProvider>(
&self,
storage: &Storage,
) -> Result<(), Storage::Error> {
self.public_group.delete(storage)?;
storage.delete_own_leaf_index(self.group_id())?;
storage.delete_group_epoch_secrets(self.group_id())?;
storage.delete_use_ratchet_tree_extension(self.group_id())?;
storage.delete_message_secrets(self.group_id())?;
storage.delete_all_resumption_psk_secrets(self.group_id())?;
self.public_group.delete(storage).await?;
storage.delete_own_leaf_index(self.group_id()).await?;
storage.delete_group_epoch_secrets(self.group_id()).await?;
storage
.delete_use_ratchet_tree_extension(self.group_id())
.await?;
storage.delete_message_secrets(self.group_id()).await?;
storage
.delete_all_resumption_psk_secrets(self.group_id())
.await?;

Ok(())
}
Expand All @@ -786,25 +807,27 @@ impl CoreGroup {
/// indexed by this group's [`GroupId`] and [`GroupEpoch`].
///
/// Returns an error if access to the key store fails.
pub(super) fn store_epoch_keypairs<Storage: StorageProvider>(
pub(super) async fn store_epoch_keypairs<Storage: StorageProvider>(
&self,
store: &Storage,
keypair_references: &[EncryptionKeyPair],
) -> Result<(), Storage::Error> {
store.write_encryption_epoch_key_pairs(
self.group_id(),
&self.context().epoch(),
self.own_leaf_index().u32(),
keypair_references,
)
store
.write_encryption_epoch_key_pairs(
self.group_id(),
&self.context().epoch(),
self.own_leaf_index().u32(),
keypair_references,
)
.await
}

/// Read the [`EncryptionKeyPair`]s of this group and its current
/// [`GroupEpoch`] from the `provider`'s storage.
///
/// Returns an empty vector if access to the store fails or it can't find
/// any keys.
pub(super) fn read_epoch_keypairs<Storage: StorageProvider>(
pub(super) async fn read_epoch_keypairs<Storage: StorageProvider>(
&self,
store: &Storage,
) -> Vec<EncryptionKeyPair> {
Expand All @@ -814,27 +837,30 @@ impl CoreGroup {
&self.context().epoch(),
self.own_leaf_index().u32(),
)
.await
.unwrap_or_default()
}

/// Delete the [`EncryptionKeyPair`]s from the previous [`GroupEpoch`] from
/// the `provider`'s key store.
///
/// Returns an error if access to the key store fails.
pub(super) fn delete_previous_epoch_keypairs<Storage: StorageProvider>(
pub(super) async fn delete_previous_epoch_keypairs<Storage: StorageProvider>(
&self,
store: &Storage,
) -> Result<(), Storage::Error> {
store.delete_encryption_epoch_key_pairs(
self.group_id(),
&GroupEpoch::from(self.context().epoch().as_u64() - 1),
self.own_leaf_index().u32(),
)
store
.delete_encryption_epoch_key_pairs(
self.group_id(),
&GroupEpoch::from(self.context().epoch().as_u64() - 1),
self.own_leaf_index().u32(),
)
.await
}

pub(crate) fn create_commit<Provider: OpenMlsProvider>(
pub(crate) async fn create_commit<Provider: OpenMlsProvider>(
&self,
mut params: CreateCommitParams,
mut params: CreateCommitParams<'_>,
provider: &Provider,
signer: &impl Signer,
) -> Result<CreateCommitResult, CreateCommitError<Provider::StorageError>> {
Expand Down Expand Up @@ -986,7 +1012,8 @@ impl CoreGroup {
provider.storage(),
&self.resumption_psk_store,
&apply_proposals_values.presharedkeys,
)?;
)
.await?;

PskSecret::new(provider.crypto(), ciphersuite, psks)?
};
Expand Down
12 changes: 8 additions & 4 deletions openmls/src/group/core_group/new_from_external_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use crate::group::core_group::*;

pub(crate) type ExternalCommitResult = (CoreGroup, CreateCommitResult);

#[cfg_attr(feature = "async", maybe_async::must_be_async)]
#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
impl CoreGroup {
/// Join a group without the help of an internal member. This function
/// requires a [GroupInfo], as well as the corresponding public tree
Expand All @@ -25,10 +27,10 @@ impl CoreGroup {
///
/// Note: If there is a group member in the group with the same identity as us,
/// this will create a remove proposal.
pub(crate) fn join_by_external_commit<Provider: OpenMlsProvider>(
pub(crate) async fn join_by_external_commit<Provider: OpenMlsProvider>(
provider: &Provider,
signer: &impl Signer,
mut params: CreateCommitParams,
mut params: CreateCommitParams<'_>,
ratchet_tree: Option<RatchetTreeIn>,
verifiable_group_info: VerifiableGroupInfo,
) -> Result<ExternalCommitResult, ExternalCommitError<Provider::StorageError>> {
Expand All @@ -53,7 +55,8 @@ impl CoreGroup {
verifiable_group_info,
// Existing proposals are discarded when joining by external commit.
ProposalStore::new(),
)?;
)
.await?;
let group_context = public_group.group_context();

// Obtain external_pub from GroupInfo extensions.
Expand Down Expand Up @@ -128,14 +131,15 @@ impl CoreGroup {
.build();

// Immediately create the commit to add ourselves to the group.
let create_commit_result = group.create_commit(params, provider, signer);
let create_commit_result = group.create_commit(params, provider, signer).await;
debug_assert!(
create_commit_result.is_ok(),
"Error creating commit {create_commit_result:?}"
);

group
.store(provider.storage())
.await
.map_err(ExternalCommitError::StorageError)?;

Ok((
Expand Down
Loading

0 comments on commit 35006f7

Please sign in to comment.