Skip to content

Commit

Permalink
feat: provide async storage interface
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonThormeyer committed Jun 19, 2024
1 parent 12c7331 commit d870e72
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 118 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"
3 changes: 3 additions & 0 deletions openmls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ openmls_memory_storage = { path = "../memory_storage", features = [
], optional = true }
openmls_test = { path = "../openmls_test", optional = true }
openmls_libcrux_crypto = { path = "../libcrux_crypto", optional = true }
maybe-async = {workspace = true}
async-trait = { workspace = true, optional = true }

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

[dev-dependencies]
backtrace = "0.3"
Expand Down
100 changes: 63 additions & 37 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 @@ -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 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())?;
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,22 +837,25 @@ 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>(
Expand Down
7 changes: 5 additions & 2 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 Down Expand Up @@ -136,6 +138,7 @@ impl CoreGroup {

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

Ok((
Expand Down
6 changes: 5 additions & 1 deletion openmls/src/group/core_group/new_from_welcome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::{
treesync::errors::{DerivePathError, PublicTreeError},
};

#[cfg_attr(feature = "async", maybe_async::must_be_async)]
#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
impl StagedCoreWelcome {
/// Create a staged join from a welcome message. The purpose of this type is to be able to
/// extract information, such as the identify of who created the welcome, before joining the
Expand Down Expand Up @@ -57,7 +59,7 @@ impl StagedCoreWelcome {
}

/// Consumes the [`StagedCoreWelcome`] and returns the respective [`CoreGroup`].
pub fn into_core_group<Provider: OpenMlsProvider>(
pub async fn into_core_group<Provider: OpenMlsProvider>(
self,
provider: &Provider,
) -> Result<CoreGroup, WelcomeError<Provider::StorageError>> {
Expand All @@ -82,9 +84,11 @@ impl StagedCoreWelcome {

group
.store(provider.storage())
.await
.map_err(WelcomeError::StorageError)?;
group
.store_epoch_keypairs(provider.storage(), group_keypairs.as_slice())
.await
.map_err(WelcomeError::StorageError)?;

Ok(group)
Expand Down
8 changes: 4 additions & 4 deletions openmls/src/group/core_group/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,13 @@ impl CoreGroup {
}

/// Helper function to read decryption keypairs.
pub(super) fn read_decryption_keypairs(
pub(super) async fn read_decryption_keypairs(
&self,
provider: &impl OpenMlsProvider,
own_leaf_nodes: &[LeafNode],
) -> Result<(Vec<EncryptionKeyPair>, Vec<EncryptionKeyPair>), StageCommitError> {
// All keys from the previous epoch are potential decryption keypairs.
let old_epoch_keypairs = self.read_epoch_keypairs(provider.storage());
let old_epoch_keypairs = self.read_epoch_keypairs(provider.storage()).await;

// If we are processing an update proposal that originally came from
// us, the keypair corresponding to the leaf in the update is also a
Expand All @@ -290,7 +290,7 @@ impl CoreGroup {
}

/// Merge a [StagedCommit] into the group after inspection
pub(crate) fn merge_staged_commit<Provider: OpenMlsProvider>(
pub(crate) async fn merge_staged_commit<Provider: OpenMlsProvider>(
&mut self,
provider: &Provider,
staged_commit: StagedCommit,
Expand All @@ -302,7 +302,7 @@ impl CoreGroup {
let leaves = self.public_group().members().collect();
// Merge the staged commit into the group state and store the secret tree from the
// previous epoch in the message secrets store.
if let Some(message_secrets) = self.merge_commit(provider, staged_commit)? {
if let Some(message_secrets) = self.merge_commit(provider, staged_commit).await? {
self.message_secrets_store
.add(past_epoch, message_secrets, leaves);
}
Expand Down
Loading

0 comments on commit d870e72

Please sign in to comment.