From 05ccb6842aeaf48df323013522a32e343268d5c1 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Wed, 1 Mar 2023 13:01:57 +0100 Subject: [PATCH 01/10] impl `KeyIdStorage` and memstore --- identity_storage/Cargo.toml | 3 + identity_storage/src/error.rs | 155 ++++++++++++++++++ .../key_id_storage/key_id_storage_error.rs | 61 +++++++ .../src/key_id_storage/memstore.rs | 114 +++++++++++++ .../src/key_id_storage/method_digest.rs | 31 ++++ identity_storage/src/key_id_storage/mod.rs | 15 ++ .../src/key_id_storage/storage.rs | 27 +++ .../src/key_storage/key_storage_error.rs | 154 +---------------- identity_storage/src/lib.rs | 4 + 9 files changed, 416 insertions(+), 148 deletions(-) create mode 100644 identity_storage/src/error.rs create mode 100644 identity_storage/src/key_id_storage/key_id_storage_error.rs create mode 100644 identity_storage/src/key_id_storage/memstore.rs create mode 100644 identity_storage/src/key_id_storage/method_digest.rs create mode 100644 identity_storage/src/key_id_storage/mod.rs create mode 100644 identity_storage/src/key_id_storage/storage.rs diff --git a/identity_storage/Cargo.toml b/identity_storage/Cargo.toml index 2952636ed5..2f8f8662aa 100644 --- a/identity_storage/Cargo.toml +++ b/identity_storage/Cargo.toml @@ -15,16 +15,19 @@ description = "Abstractions over storage for cryptographic keys used in DID Docu async-trait = { version = "0.1.64", default-features = false } identity_core = { version = "=0.7.0-alpha.5", path = "../identity_core", default-features = false } identity_jose = { version = "=0.7.0-alpha.5", path = "../identity_jose", default-features = false } +identity_verification = {version = "=0.7.0-alpha.5", path = "../identity_verification", default_features = false } iota-crypto = { version = "0.15", default-features = false, features = ["blake2b", "ed25519", "random"], optional = true } rand = { version = "0.8.5", default-features = false, features = ["std"], optional = true } serde.workspace = true serde_json.workspace = true thiserror.workspace = true tokio = { version = "1.23.0", default-features = false, features = ["macros", "sync"], optional = true } +seahash = { version = "4.1.0", default_features = false } [dev-dependencies] rand = { version = "0.8.5" } tokio = { version = "1.23.0", default-features = false, features = ["macros", "sync", "rt"] } +identity_did = { version = "=0.7.0-alpha.5", path = "../identity_did", default-features = false } [features] # Exposes in-memory implementations of the storage traits intended exclusively for testing. diff --git a/identity_storage/src/error.rs b/identity_storage/src/error.rs new file mode 100644 index 0000000000..4f6a0edd60 --- /dev/null +++ b/identity_storage/src/error.rs @@ -0,0 +1,155 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::borrow::Cow; +use std::error::Error; +use std::fmt::Debug; +use std::fmt::Display; + +/// The error type for key storage operations. +/// +/// Instances always carry a corresponding [`StorageErrorKind`] and may be extended with custom error messages and +/// source. +#[derive(Debug)] +pub struct StorageError { + repr: Repr, +} + +pub trait StorageErrorKind: Display + Debug { + fn description(&self) -> &str; +} + +impl Display for StorageError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.repr { + Repr::Simple(ref cause) => write!(f, "{}", cause.description()), + Repr::Extensive(ref extensive) => { + write!(f, "{}", extensive.cause.description())?; + let Some(ref message) = extensive.message else {return Ok(())}; + write!(f, " message: {}", message.as_ref()) + } + } + } +} + +impl Error for StorageError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.extensive().and_then(|err| { + err + .source + .as_ref() + .map(|source| source.as_ref() as &(dyn Error + 'static)) + }) + } +} + +#[derive(Debug)] +struct Extensive { + cause: T, + source: Option>, + message: Option>, +} + +#[derive(Debug)] +enum Repr { + Simple(T), + Extensive(Box>), +} + +impl From for StorageError { + fn from(cause: T) -> Self { + Self::new(cause) + } +} + +impl From>> for StorageError { + fn from(extensive: Box>) -> Self { + Self { + repr: Repr::Extensive(extensive), + } + } +} + +impl StorageError { + /// Constructs a new [`StorageError`]. + pub fn new(cause: T) -> Self { + Self { + repr: Repr::Simple(cause), + } + } + + /// Returns a reference to corresponding [`StorageErrorKind`] of this error. + pub fn kind(&self) -> &T { + match self.repr { + Repr::Simple(ref cause) => cause, + Repr::Extensive(ref extensive) => &extensive.cause, + } + } + + /// Converts this error into the corresponding [`StorageErrorKind`] of this error. + pub fn into_kind(self) -> T { + match self.repr { + Repr::Simple(cause) => cause, + Repr::Extensive(extensive) => extensive.cause, + } + } + + /// Returns a reference to the custom message of the [`StorageError`] if it was set. + pub fn custom_message(&self) -> Option<&str> { + self + .extensive() + .into_iter() + .flat_map(|extensive| extensive.message.as_deref()) + .next() + } + + /// Returns a reference to the attached source of the [`StorageError`] if it was set. + pub fn source_ref(&self) -> Option<&(dyn Error + Send + Sync + 'static)> { + self.extensive().and_then(|extensive| extensive.source.as_deref()) + } + + /// Converts this error into the source error if it was set. + pub fn into_source(self) -> Option> { + self.into_extensive().source + } + + fn extensive(&self) -> Option<&Extensive> { + match self.repr { + Repr::Extensive(ref extensive) => Some(extensive.as_ref()), + _ => None, + } + } + + fn into_extensive(self) -> Box> { + match self.repr { + Repr::Extensive(extensive) => extensive, + Repr::Simple(cause) => Box::new(Extensive { + cause, + source: None, + message: None, + }), + } + } + + /// Updates the `source` of the [`StorageError`]. + pub fn with_source(self, source: impl Into>) -> Self { + self._with_source(source.into()) + } + + fn _with_source(self, source: Box) -> Self { + let mut extensive = self.into_extensive(); + extensive.as_mut().source = Some(source); + Self::from(extensive) + } + + /// Updates the custom message of the [`StorageError`]. + pub fn with_custom_message(self, message: impl Into>) -> Self { + self._with_custom_message(message.into()) + } + + fn _with_custom_message(self, message: Cow<'static, str>) -> Self { + let mut extensive = self.into_extensive(); + extensive.as_mut().message = Some(message); + Self::from(extensive) + } +} diff --git a/identity_storage/src/key_id_storage/key_id_storage_error.rs b/identity_storage/src/key_id_storage/key_id_storage_error.rs new file mode 100644 index 0000000000..236fbd0fdf --- /dev/null +++ b/identity_storage/src/key_id_storage/key_id_storage_error.rs @@ -0,0 +1,61 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::fmt::Display; + +use crate::StorageError; +use crate::StorageErrorKind; + +pub type KeyIdStorageError = StorageError; + +/// The cause of the failed key id storage operation. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum KeyIdStorageErrorKind { + /// Indicates that the key id storage implementation is not able to find the requested key id. + KeyIdNotFound, + + /// Indicates that the storage is unavailable for an unpredictable amount of time. + /// + /// Occurrences of this variant should hopefully be rare, but could occur if hardware fails, or a hosted key store + /// goes offline. + Unavailable, + + /// Indicates that an attempt was made to authenticate with the key storage, but the operation did not succeed. + Unauthenticated, + + /// Indicates an unsuccessful I/O operation that may be retried, such as a temporary connection failure or timeouts. + /// + /// Returning this error signals to the caller that the operation may be retried with a chance of success. + /// It is at the caller's discretion whether to retry or not, and how often. + RetryableIOFailure, + + /// Indicates a failure to serialize or deserialize. + SerializationError, + + /// Indicates that something went wrong, but it is unclear whether the reason matches any of the other variants. + /// + /// When using this variant one may want to attach additional context to the corresponding [`StorageError`]. See + /// [`KeyStorageError::with_custom_message`](KeyStorageError::with_custom_message()) and + /// [`KeyStorageError::with_source`](KeyStorageError::with_source()). + Unspecified, +} + +impl StorageErrorKind for KeyIdStorageErrorKind { + fn description(&self) -> &str { + match self { + Self::KeyIdNotFound => "key id not found", + Self::Unavailable => "key id storage unavailable", + Self::Unauthenticated => "authentication with the key id storage failed", + Self::Unspecified => "key storage operation failed", + Self::RetryableIOFailure => "key id storage was unsuccessful because of an I/O failure", + Self::SerializationError => "(de)serialization error", + } + } +} + +impl Display for KeyIdStorageErrorKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.description()) + } +} diff --git a/identity_storage/src/key_id_storage/memstore.rs b/identity_storage/src/key_id_storage/memstore.rs new file mode 100644 index 0000000000..856bfd35fb --- /dev/null +++ b/identity_storage/src/key_id_storage/memstore.rs @@ -0,0 +1,114 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use crate::key_id_storage::key_id_storage_error::KeyIdStorageError; +use crate::key_id_storage::key_id_storage_error::KeyIdStorageErrorKind; +use crate::key_id_storage::storage::KeyIdStorage; +use crate::key_storage::shared::Shared; +use crate::key_storage::KeyId; +use async_trait::async_trait; +use std::collections::HashMap; +use tokio::sync::RwLockReadGuard; +use tokio::sync::RwLockWriteGuard; + +use super::method_digest::MethodDigest; +use super::storage::KeyIdStorageResult; + +type KeyIdStore = HashMap; + +/// An insecure, in-memory [`KeyIdStorage`] implementation that serves as an example and may be used in tests. +#[derive(Debug)] +pub struct KeyIdMemstore { + key_id_store: Shared, +} + +impl KeyIdMemstore { + /// Creates a new, empty `KeyIdMemstore` instance. + pub fn new() -> Self { + Self { + key_id_store: Shared::new(HashMap::new()), + } + } +} + +impl Default for KeyIdMemstore { + fn default() -> Self { + Self::new() + } +} + +#[cfg_attr(not(feature = "send-sync-storage"), async_trait(? Send))] +#[cfg_attr(feature = "send-sync-storage", async_trait)] +impl KeyIdStorage for KeyIdMemstore { + async fn insert_key_id(&self, key: MethodDigest, value: KeyId) -> KeyIdStorageResult<()> { + let mut key_id_store: RwLockWriteGuard<'_, KeyIdStore> = self.key_id_store.write().await; + key_id_store.insert(key, value); + Ok(()) + } + + /// Obtain the `KeyId` associated with the given `key`. + async fn get_key_id(&self, key: &MethodDigest) -> KeyIdStorageResult { + let key_id_store: RwLockReadGuard<'_, KeyIdStore> = self.key_id_store.read().await; + Ok( + key_id_store + .get(key) + .ok_or_else(|| KeyIdStorageError::new(KeyIdStorageErrorKind::KeyIdNotFound))? + .clone(), + ) + } + + /// Delete the [`KeyId`] associated with the given [`MethodDigest`] from the [`KeyIdStorage`]. + /// Errors if `key` is not found in storage. + async fn delete_key_id(&self, key: &MethodDigest) -> KeyIdStorageResult<()> { + let mut key_id_store: RwLockWriteGuard<'_, KeyIdStore> = self.key_id_store.write().await; + key_id_store + .remove(key) + .ok_or_else(|| KeyIdStorageError::new(KeyIdStorageErrorKind::KeyIdNotFound))?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::key_id_storage::memstore::KeyIdMemstore; + use crate::key_id_storage::method_digest::MethodDigest; + use crate::key_id_storage::storage::KeyIdStorage; + use crate::key_id_storage::KeyIdStorageError; + use crate::key_id_storage::KeyIdStorageErrorKind; + use crate::key_storage::KeyId; + use identity_core::crypto::KeyPair; + use identity_core::crypto::KeyType; + use identity_core::utils::BaseEncoding; + use identity_did::CoreDID; + use identity_verification::VerificationMethod; + + #[tokio::test] + pub async fn memstore_operations() { + // Create a Verification Method. + let keypair: KeyPair = KeyPair::new(KeyType::Ed25519).unwrap(); + let did: CoreDID = + CoreDID::parse(format!("did:example:{}", BaseEncoding::encode_base58(keypair.public()))).unwrap(); + let verification_method: VerificationMethod = + VerificationMethod::new(did, KeyType::Ed25519, keypair.public(), "frag_1").unwrap(); + + // Test insertion. + let memstore: KeyIdMemstore = KeyIdMemstore::new(); + let key_id_1 = KeyId::new("keyid"); + let method_digest: MethodDigest = MethodDigest::new(&verification_method).unwrap(); + memstore + .insert_key_id(method_digest.clone(), key_id_1.clone()) + .await + .expect("inserting into memstore failed"); + + // Test retrieving. + let key_id: KeyId = memstore.get_key_id(&method_digest).await.unwrap(); + assert_eq!(key_id_1, key_id); + + // Test deletion. + memstore.delete_key_id(&method_digest).await.expect("deletion failed"); + + let repeat_deletion_result: Result<(), KeyIdStorageError> = memstore.delete_key_id(&method_digest).await; + let _expected_error: KeyIdStorageError = KeyIdStorageError::new(KeyIdStorageErrorKind::KeyIdNotFound); + assert!(matches!(repeat_deletion_result.unwrap_err(), _expected_error)); + } +} diff --git a/identity_storage/src/key_id_storage/method_digest.rs b/identity_storage/src/key_id_storage/method_digest.rs new file mode 100644 index 0000000000..9bb85cb6da --- /dev/null +++ b/identity_storage/src/key_id_storage/method_digest.rs @@ -0,0 +1,31 @@ +use std::hash::Hasher; + +use identity_verification::VerificationMethod; +use seahash::SeaHasher; + +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct MethodDigest { + pub version: u8, + pub value: u64, +} + +impl MethodDigest { + pub fn new(verification_method: &VerificationMethod) -> identity_verification::Result { + let mut hasher: SeaHasher = SeaHasher::new(); + let fragment = verification_method + .id() + .fragment() + .ok_or(identity_verification::Error::MissingIdFragment)?; + + let method_data: Vec = verification_method.data().try_decode()?; + hasher.write(fragment.as_bytes()); + hasher.write(&method_data); + let key_hash: u64 = hasher.finish(); + Ok(Self { + version: 0, + value: key_hash, + }) + } +} diff --git a/identity_storage/src/key_id_storage/mod.rs b/identity_storage/src/key_id_storage/mod.rs new file mode 100644 index 0000000000..11af300ca2 --- /dev/null +++ b/identity_storage/src/key_id_storage/mod.rs @@ -0,0 +1,15 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +mod key_id_storage_error; +mod method_digest; +mod storage; + +#[cfg(feature = "memstore")] +mod memstore; + +pub use key_id_storage_error::*; +#[cfg(feature = "memstore")] +pub use memstore::*; +pub use method_digest::*; +pub use storage::*; diff --git a/identity_storage/src/key_id_storage/storage.rs b/identity_storage/src/key_id_storage/storage.rs new file mode 100644 index 0000000000..724a09e919 --- /dev/null +++ b/identity_storage/src/key_id_storage/storage.rs @@ -0,0 +1,27 @@ +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use crate::key_storage::KeyId; +use async_trait::async_trait; + +use super::key_id_storage_error::KeyIdStorageError; +use super::method_digest::MethodDigest; + +pub type KeyIdStorageResult = Result; + +/// Storing +#[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))] +#[cfg_attr(feature = "send-sync-storage", async_trait)] +pub trait KeyIdStorage { + /// Insert a [`KeyId`] into the [`KeyIdStorage`] under the given [`MethodDigest`]. + /// If an entry for `key` already exists in the storage an error must be returned + /// immediately without altering the state the storage. + async fn insert_key_id(&self, key: MethodDigest, value: KeyId) -> KeyIdStorageResult<()>; + + /// Obtain the [`KeyId`] associated with the given [`MethodDigest`]. + async fn get_key_id(&self, key: &MethodDigest) -> KeyIdStorageResult; + + /// Delete the [`KeyId`] associated with the given [`MethodDigest`] from the [`IdentityStorage`]. + /// If `key` is not found in storage, an Error must be returned. + async fn delete_key_id(&self, key: &MethodDigest) -> KeyIdStorageResult<()>; +} diff --git a/identity_storage/src/key_storage/key_storage_error.rs b/identity_storage/src/key_storage/key_storage_error.rs index 226443114d..01982ba8d8 100644 --- a/identity_storage/src/key_storage/key_storage_error.rs +++ b/identity_storage/src/key_storage/key_storage_error.rs @@ -1,153 +1,12 @@ // Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use std::borrow::Cow; -use std::error::Error; use std::fmt::Display; -/// The error type for key storage operations. -/// -/// Instances always carry a corresponding [`KeyStorageErrorKind`] and may be extended with custom error messages and -/// source. -#[derive(Debug)] -pub struct KeyStorageError { - repr: Repr, -} - -impl Display for KeyStorageError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.repr { - Repr::Simple(ref cause) => write!(f, "{}", cause.as_str()), - Repr::Extensive(ref extensive) => { - write!(f, "{}", extensive.cause.as_str())?; - let Some(ref message) = extensive.message else {return Ok(())}; - write!(f, " message: {}", message.as_ref()) - } - } - } -} - -impl Error for KeyStorageError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - self.extensive().and_then(|err| { - err - .source - .as_ref() - .map(|source| source.as_ref() as &(dyn Error + 'static)) - }) - } -} - -#[derive(Debug)] -struct Extensive { - cause: KeyStorageErrorKind, - source: Option>, - message: Option>, -} - -#[derive(Debug)] -enum Repr { - Simple(KeyStorageErrorKind), - Extensive(Box), -} +use crate::error::StorageError; +use crate::error::StorageErrorKind; -impl From for KeyStorageError { - fn from(cause: KeyStorageErrorKind) -> Self { - Self::new(cause) - } -} - -impl From> for KeyStorageError { - fn from(extensive: Box) -> Self { - Self { - repr: Repr::Extensive(extensive), - } - } -} - -impl KeyStorageError { - /// Constructs a new [`KeyStorageError`]. - pub fn new(cause: KeyStorageErrorKind) -> Self { - Self { - repr: Repr::Simple(cause), - } - } - - /// Returns a reference to corresponding [`KeyStorageErrorKind`] of this error. - pub fn kind(&self) -> &KeyStorageErrorKind { - match self.repr { - Repr::Simple(ref cause) => cause, - Repr::Extensive(ref extensive) => &extensive.cause, - } - } - - /// Converts this error into the corresponding [`KeyStorageErrorKind`] of this error. - pub fn into_kind(self) -> KeyStorageErrorKind { - match self.repr { - Repr::Simple(cause) => cause, - Repr::Extensive(extensive) => extensive.cause, - } - } - - /// Returns a reference to the custom message of the [`KeyStorageError`] if it was set. - pub fn custom_message(&self) -> Option<&str> { - self - .extensive() - .into_iter() - .flat_map(|extensive| extensive.message.as_deref()) - .next() - } - - /// Returns a reference to the attached source of the [`KeyStorageError`] if it was set. - pub fn source_ref(&self) -> Option<&(dyn Error + Send + Sync + 'static)> { - self.extensive().and_then(|extensive| extensive.source.as_deref()) - } - - /// Converts this error into the source error if it was set. - pub fn into_source(self) -> Option> { - self.into_extensive().source - } - - fn extensive(&self) -> Option<&Extensive> { - match self.repr { - Repr::Extensive(ref extensive) => Some(extensive.as_ref()), - _ => None, - } - } - - fn into_extensive(self) -> Box { - match self.repr { - Repr::Extensive(extensive) => extensive, - Repr::Simple(cause) => Box::new(Extensive { - cause, - source: None, - message: None, - }), - } - } - - /// Updates the `source` of the [`KeyStorageError`]. - pub fn with_source(self, source: impl Into>) -> Self { - self._with_source(source.into()) - } - - fn _with_source(self, source: Box) -> Self { - let mut extensive = self.into_extensive(); - extensive.as_mut().source = Some(source); - Self::from(extensive) - } - - /// Updates the custom message of the [`KeyStorageError`]. - pub fn with_custom_message(self, message: impl Into>) -> Self { - self._with_custom_message(message.into()) - } - - fn _with_custom_message(self, message: Cow<'static, str>) -> Self { - let mut extensive = self.into_extensive(); - extensive.as_mut().message = Some(message); - Self::from(extensive) - } -} +pub type KeyStorageError = StorageError; /// The cause of the failed key storage operation. #[derive(Debug, Clone)] @@ -193,9 +52,8 @@ pub enum KeyStorageErrorKind { Unspecified, } -impl KeyStorageErrorKind { - /// Returns a report friendly representation of the [`KeyStorageErrorCause`]. - const fn as_str(&self) -> &str { +impl StorageErrorKind for KeyStorageErrorKind { + fn description(&self) -> &str { match self { Self::UnsupportedKeyType => "key generation failed: the provided multikey schema is not supported", Self::KeyAlgorithmMismatch => "the key type cannot be used with the algorithm", @@ -212,6 +70,6 @@ impl KeyStorageErrorKind { impl Display for KeyStorageErrorKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.as_str()) + write!(f, "{}", self.description()) } } diff --git a/identity_storage/src/lib.rs b/identity_storage/src/lib.rs index debe7f5132..45087e2730 100644 --- a/identity_storage/src/lib.rs +++ b/identity_storage/src/lib.rs @@ -1,4 +1,8 @@ // Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +pub mod error; +pub mod key_id_storage; pub mod key_storage; + +pub use error::*; From 6b32d5f15b5ecfaf41a76a78fd3a16a154f27c5c Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Wed, 1 Mar 2023 13:33:42 +0100 Subject: [PATCH 02/10] fix docs --- identity_storage/src/key_id_storage/method_digest.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/identity_storage/src/key_id_storage/method_digest.rs b/identity_storage/src/key_id_storage/method_digest.rs index 9bb85cb6da..ad261229b4 100644 --- a/identity_storage/src/key_id_storage/method_digest.rs +++ b/identity_storage/src/key_id_storage/method_digest.rs @@ -1,17 +1,21 @@ -use std::hash::Hasher; +// Copyright 2020-2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 +use std::hash::Hasher; use identity_verification::VerificationMethod; use seahash::SeaHasher; -// Copyright 2020-2023 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 +/// Unique description through hashing of key materials in `VerificationMethod`s. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct MethodDigest { + /// Version of hashing. pub version: u8, + /// Hash value. pub value: u64, } impl MethodDigest { + /// Creates a new [`MethodDigest`]. pub fn new(verification_method: &VerificationMethod) -> identity_verification::Result { let mut hasher: SeaHasher = SeaHasher::new(); let fragment = verification_method From b44748735fa6e801ec7cdc9280988649e176705f Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Wed, 1 Mar 2023 13:35:04 +0100 Subject: [PATCH 03/10] dprint fmt --- identity_storage/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/identity_storage/Cargo.toml b/identity_storage/Cargo.toml index 2f8f8662aa..4321e1cfc9 100644 --- a/identity_storage/Cargo.toml +++ b/identity_storage/Cargo.toml @@ -15,19 +15,19 @@ description = "Abstractions over storage for cryptographic keys used in DID Docu async-trait = { version = "0.1.64", default-features = false } identity_core = { version = "=0.7.0-alpha.5", path = "../identity_core", default-features = false } identity_jose = { version = "=0.7.0-alpha.5", path = "../identity_jose", default-features = false } -identity_verification = {version = "=0.7.0-alpha.5", path = "../identity_verification", default_features = false } +identity_verification = { version = "=0.7.0-alpha.5", path = "../identity_verification", default_features = false } iota-crypto = { version = "0.15", default-features = false, features = ["blake2b", "ed25519", "random"], optional = true } rand = { version = "0.8.5", default-features = false, features = ["std"], optional = true } +seahash = { version = "4.1.0", default_features = false } serde.workspace = true serde_json.workspace = true thiserror.workspace = true tokio = { version = "1.23.0", default-features = false, features = ["macros", "sync"], optional = true } -seahash = { version = "4.1.0", default_features = false } [dev-dependencies] +identity_did = { version = "=0.7.0-alpha.5", path = "../identity_did", default-features = false } rand = { version = "0.8.5" } tokio = { version = "1.23.0", default-features = false, features = ["macros", "sync", "rt"] } -identity_did = { version = "=0.7.0-alpha.5", path = "../identity_did", default-features = false } [features] # Exposes in-memory implementations of the storage traits intended exclusively for testing. From ca75ba20942cfeaac776499125ce5093ff1f8f84 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Wed, 1 Mar 2023 13:40:29 +0100 Subject: [PATCH 04/10] fix docs --- identity_storage/src/key_id_storage/key_id_storage_error.rs | 4 ++-- identity_storage/src/key_id_storage/storage.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/identity_storage/src/key_id_storage/key_id_storage_error.rs b/identity_storage/src/key_id_storage/key_id_storage_error.rs index 236fbd0fdf..84efc97e93 100644 --- a/identity_storage/src/key_id_storage/key_id_storage_error.rs +++ b/identity_storage/src/key_id_storage/key_id_storage_error.rs @@ -36,8 +36,8 @@ pub enum KeyIdStorageErrorKind { /// Indicates that something went wrong, but it is unclear whether the reason matches any of the other variants. /// /// When using this variant one may want to attach additional context to the corresponding [`StorageError`]. See - /// [`KeyStorageError::with_custom_message`](KeyStorageError::with_custom_message()) and - /// [`KeyStorageError::with_source`](KeyStorageError::with_source()). + /// [`KeyStorageError::with_custom_message`](KeyIdStorageError::with_custom_message()) and + /// [`KeyStorageError::with_source`](KeyIdStorageError::with_source()). Unspecified, } diff --git a/identity_storage/src/key_id_storage/storage.rs b/identity_storage/src/key_id_storage/storage.rs index 724a09e919..6108f27f4c 100644 --- a/identity_storage/src/key_id_storage/storage.rs +++ b/identity_storage/src/key_id_storage/storage.rs @@ -21,7 +21,7 @@ pub trait KeyIdStorage { /// Obtain the [`KeyId`] associated with the given [`MethodDigest`]. async fn get_key_id(&self, key: &MethodDigest) -> KeyIdStorageResult; - /// Delete the [`KeyId`] associated with the given [`MethodDigest`] from the [`IdentityStorage`]. + /// Delete the [`KeyId`] associated with the given [`MethodDigest`] from the [`KeyIdStorage`]. /// If `key` is not found in storage, an Error must be returned. async fn delete_key_id(&self, key: &MethodDigest) -> KeyIdStorageResult<()>; } From b7034458e13177a14a2a04156d2563b89dcba0df Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Wed, 1 Mar 2023 13:47:58 +0100 Subject: [PATCH 05/10] fmt --- identity_storage/src/key_id_storage/method_digest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/identity_storage/src/key_id_storage/method_digest.rs b/identity_storage/src/key_id_storage/method_digest.rs index ad261229b4..cdb4ca44ec 100644 --- a/identity_storage/src/key_id_storage/method_digest.rs +++ b/identity_storage/src/key_id_storage/method_digest.rs @@ -1,9 +1,9 @@ // Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use std::hash::Hasher; use identity_verification::VerificationMethod; use seahash::SeaHasher; +use std::hash::Hasher; /// Unique description through hashing of key materials in `VerificationMethod`s. #[derive(Clone, Debug, PartialEq, Eq, Hash)] From 977de35af1b07c6860675aa1ac2af2510ad8fe09 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Tue, 7 Mar 2023 19:32:02 +0100 Subject: [PATCH 06/10] code review --- identity_storage/src/error.rs | 1 + .../{storage.rs => key_id_storage.rs} | 5 +- .../key_id_storage/key_id_storage_error.rs | 5 + .../src/key_id_storage/memstore.rs | 17 ++- .../src/key_id_storage/method_digest.rs | 122 +++++++++++++++++- identity_storage/src/key_id_storage/mod.rs | 5 +- .../src/key_storage/jwk_storage.rs | 1 + .../src/key_storage/key_storage_error.rs | 1 + 8 files changed, 144 insertions(+), 13 deletions(-) rename identity_storage/src/key_id_storage/{storage.rs => key_id_storage.rs} (91%) diff --git a/identity_storage/src/error.rs b/identity_storage/src/error.rs index 4f6a0edd60..3c6119a3a4 100644 --- a/identity_storage/src/error.rs +++ b/identity_storage/src/error.rs @@ -15,6 +15,7 @@ pub struct StorageError { repr: Repr, } +/// Error types that can happen during storage operations. pub trait StorageErrorKind: Display + Debug { fn description(&self) -> &str; } diff --git a/identity_storage/src/key_id_storage/storage.rs b/identity_storage/src/key_id_storage/key_id_storage.rs similarity index 91% rename from identity_storage/src/key_id_storage/storage.rs rename to identity_storage/src/key_id_storage/key_id_storage.rs index 6108f27f4c..60c77dff58 100644 --- a/identity_storage/src/key_id_storage/storage.rs +++ b/identity_storage/src/key_id_storage/key_id_storage.rs @@ -7,14 +7,16 @@ use async_trait::async_trait; use super::key_id_storage_error::KeyIdStorageError; use super::method_digest::MethodDigest; +/// Result of key id storage operations. pub type KeyIdStorageResult = Result; -/// Storing +/// Key value Storage for [`KeyId`] under [`MethodDigest`]. #[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))] #[cfg_attr(feature = "send-sync-storage", async_trait)] pub trait KeyIdStorage { /// Insert a [`KeyId`] into the [`KeyIdStorage`] under the given [`MethodDigest`]. /// If an entry for `key` already exists in the storage an error must be returned + /// /// immediately without altering the state the storage. async fn insert_key_id(&self, key: MethodDigest, value: KeyId) -> KeyIdStorageResult<()>; @@ -22,6 +24,7 @@ pub trait KeyIdStorage { async fn get_key_id(&self, key: &MethodDigest) -> KeyIdStorageResult; /// Delete the [`KeyId`] associated with the given [`MethodDigest`] from the [`KeyIdStorage`]. + /// /// If `key` is not found in storage, an Error must be returned. async fn delete_key_id(&self, key: &MethodDigest) -> KeyIdStorageResult<()>; } diff --git a/identity_storage/src/key_id_storage/key_id_storage_error.rs b/identity_storage/src/key_id_storage/key_id_storage_error.rs index 84efc97e93..2ea4d2315b 100644 --- a/identity_storage/src/key_id_storage/key_id_storage_error.rs +++ b/identity_storage/src/key_id_storage/key_id_storage_error.rs @@ -6,6 +6,7 @@ use std::fmt::Display; use crate::StorageError; use crate::StorageErrorKind; +/// Error type for key id storage operations. pub type KeyIdStorageError = StorageError; /// The cause of the failed key id storage operation. @@ -15,6 +16,9 @@ pub enum KeyIdStorageErrorKind { /// Indicates that the key id storage implementation is not able to find the requested key id. KeyIdNotFound, + /// Indicates that the key id already exists in the storage. + KeyIdAlreadyExists, + /// Indicates that the storage is unavailable for an unpredictable amount of time. /// /// Occurrences of this variant should hopefully be rare, but could occur if hardware fails, or a hosted key store @@ -44,6 +48,7 @@ pub enum KeyIdStorageErrorKind { impl StorageErrorKind for KeyIdStorageErrorKind { fn description(&self) -> &str { match self { + Self::KeyIdAlreadyExists => "Key id already exists in storage", Self::KeyIdNotFound => "key id not found", Self::Unavailable => "key id storage unavailable", Self::Unauthenticated => "authentication with the key id storage failed", diff --git a/identity_storage/src/key_id_storage/memstore.rs b/identity_storage/src/key_id_storage/memstore.rs index 856bfd35fb..aef9c87821 100644 --- a/identity_storage/src/key_id_storage/memstore.rs +++ b/identity_storage/src/key_id_storage/memstore.rs @@ -1,9 +1,9 @@ // Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use crate::key_id_storage::key_id_storage::KeyIdStorage; use crate::key_id_storage::key_id_storage_error::KeyIdStorageError; use crate::key_id_storage::key_id_storage_error::KeyIdStorageErrorKind; -use crate::key_id_storage::storage::KeyIdStorage; use crate::key_storage::shared::Shared; use crate::key_storage::KeyId; use async_trait::async_trait; @@ -11,8 +11,8 @@ use std::collections::HashMap; use tokio::sync::RwLockReadGuard; use tokio::sync::RwLockWriteGuard; +use super::key_id_storage::KeyIdStorageResult; use super::method_digest::MethodDigest; -use super::storage::KeyIdStorageResult; type KeyIdStore = HashMap; @@ -42,11 +42,13 @@ impl Default for KeyIdMemstore { impl KeyIdStorage for KeyIdMemstore { async fn insert_key_id(&self, key: MethodDigest, value: KeyId) -> KeyIdStorageResult<()> { let mut key_id_store: RwLockWriteGuard<'_, KeyIdStore> = self.key_id_store.write().await; + if key_id_store.contains_key(&key) { + return Err(KeyIdStorageError::new(KeyIdStorageErrorKind::KeyIdAlreadyExists)); + } key_id_store.insert(key, value); Ok(()) } - /// Obtain the `KeyId` associated with the given `key`. async fn get_key_id(&self, key: &MethodDigest) -> KeyIdStorageResult { let key_id_store: RwLockReadGuard<'_, KeyIdStore> = self.key_id_store.read().await; Ok( @@ -57,8 +59,6 @@ impl KeyIdStorage for KeyIdMemstore { ) } - /// Delete the [`KeyId`] associated with the given [`MethodDigest`] from the [`KeyIdStorage`]. - /// Errors if `key` is not found in storage. async fn delete_key_id(&self, key: &MethodDigest) -> KeyIdStorageResult<()> { let mut key_id_store: RwLockWriteGuard<'_, KeyIdStore> = self.key_id_store.write().await; key_id_store @@ -70,9 +70,9 @@ impl KeyIdStorage for KeyIdMemstore { #[cfg(test)] mod tests { + use crate::key_id_storage::key_id_storage::KeyIdStorage; use crate::key_id_storage::memstore::KeyIdMemstore; use crate::key_id_storage::method_digest::MethodDigest; - use crate::key_id_storage::storage::KeyIdStorage; use crate::key_id_storage::KeyIdStorageError; use crate::key_id_storage::KeyIdStorageErrorKind; use crate::key_storage::KeyId; @@ -100,6 +100,11 @@ mod tests { .await .expect("inserting into memstore failed"); + // Double insertion. + let insertion_result = memstore.insert_key_id(method_digest.clone(), key_id_1.clone()).await; + let _expected_error: KeyIdStorageError = KeyIdStorageError::new(KeyIdStorageErrorKind::KeyIdAlreadyExists); + assert!(matches!(insertion_result.unwrap_err(), _expected_error)); + // Test retrieving. let key_id: KeyId = memstore.get_key_id(&method_digest).await.unwrap(); assert_eq!(key_id_1, key_id); diff --git a/identity_storage/src/key_id_storage/method_digest.rs b/identity_storage/src/key_id_storage/method_digest.rs index cdb4ca44ec..109354b796 100644 --- a/identity_storage/src/key_id_storage/method_digest.rs +++ b/identity_storage/src/key_id_storage/method_digest.rs @@ -5,20 +5,22 @@ use identity_verification::VerificationMethod; use seahash::SeaHasher; use std::hash::Hasher; -/// Unique description through hashing of key materials in `VerificationMethod`s. +use super::KeyIdStorageError; + +/// Unique identifier of a [`VerificationMethod`]. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct MethodDigest { /// Version of hashing. - pub version: u8, + version: u8, /// Hash value. - pub value: u64, + value: u64, } impl MethodDigest { /// Creates a new [`MethodDigest`]. pub fn new(verification_method: &VerificationMethod) -> identity_verification::Result { let mut hasher: SeaHasher = SeaHasher::new(); - let fragment = verification_method + let fragment: &str = verification_method .id() .fragment() .ok_or(identity_verification::Error::MissingIdFragment)?; @@ -32,4 +34,116 @@ impl MethodDigest { value: key_hash, }) } + + /// Packs [`MethodDigest`] into bytes. + pub fn pack(&self) -> Vec { + let mut pack: Vec = vec![self.version]; + pack.append(&mut self.value.to_le_bytes().to_vec()); + pack + } + + /// Unpacks bytes into [`MethodDigest`]. + pub fn unpack(bytes: Vec) -> crate::key_id_storage::KeyIdStorageResult { + if bytes.len() != 9 { + return Err(KeyIdStorageError::new(super::KeyIdStorageErrorKind::SerializationError)); + } + let version: u8 = bytes[0]; + if version != 0 { + return Err(KeyIdStorageError::new(super::KeyIdStorageErrorKind::SerializationError)); + } + let value_le_bytes: [u8; 8] = bytes[1..9] + .try_into() + .map_err(|_| KeyIdStorageError::new(super::KeyIdStorageErrorKind::SerializationError))?; + let value: u64 = u64::from_le_bytes(value_le_bytes); + Ok(Self { version, value }) + } +} + +#[cfg(test)] +mod test { + use crate::key_id_storage::KeyIdStorageErrorKind; + use crate::StorageError; + use identity_core::convert::FromJson; + use identity_core::crypto::KeyPair; + use identity_core::crypto::KeyType; + use identity_core::json; + use identity_core::utils::BaseEncoding; + use identity_did::CoreDID; + use identity_verification::VerificationMethod; + use serde_json::Value; + + use super::MethodDigest; + + #[test] + pub fn hash() { + // These values should be tested in the bindings too. + let a: Value = json!( + { + "id": "did:example:HHoh9NQC9AUsK15Jyyq53VTujxEUizKDXRXd7zbT1B5u#frag_1", + "controller": "did:example:HHoh9NQC9AUsK15Jyyq53VTujxEUizKDXRXd7zbT1B5u", + "type": "Ed25519VerificationKey2018", + "publicKeyMultibase": "zHHoh9NQC9AUsK15Jyyq53VTujxEUizKDXRXd7zbT1B5u" + } + ); + let verification_method: VerificationMethod = VerificationMethod::from_json_value(a).unwrap(); + let method_digest: MethodDigest = MethodDigest::new(&verification_method).unwrap(); + let method_digest_expected: MethodDigest = MethodDigest { + version: 0, + value: 9634551232492878922, + }; + assert_eq!(method_digest, method_digest_expected); + } + + #[test] + pub fn pack() { + let verification_method: VerificationMethod = create_verification_method(); + let method_digest: MethodDigest = MethodDigest::new(&verification_method).unwrap(); + let packed: Vec = method_digest.pack(); + let method_digest_unpacked: MethodDigest = MethodDigest::unpack(packed).unwrap(); + assert_eq!(method_digest, method_digest_unpacked); + } + + #[test] + pub fn unpack() { + let packed: Vec = vec![0, 255, 212, 82, 63, 57, 19, 134, 193]; + let method_digest_unpacked: MethodDigest = MethodDigest::unpack(packed).unwrap(); + let method_digest_expected: MethodDigest = MethodDigest { + version: 0, + value: 13944854432795776255, + }; + assert_eq!(method_digest_unpacked, method_digest_expected); + } + + #[test] + pub fn invalid_unpack() { + let packed: Vec = vec![1, 255, 212, 82, 63, 57, 19, 134, 193]; + let method_digest_unpacked = MethodDigest::unpack(packed).unwrap_err(); + let _expected_error = StorageError::new(KeyIdStorageErrorKind::SerializationError); + assert!(matches!(method_digest_unpacked, _expected_error)); + + // Vec size > 9. + let packed: Vec = vec![1, 255, 212, 82, 63, 57, 19, 134, 193, 200]; + let method_digest_unpacked = MethodDigest::unpack(packed).unwrap_err(); + let _expected_error = StorageError::new(KeyIdStorageErrorKind::SerializationError); + assert!(matches!(method_digest_unpacked, _expected_error)); + + // Vec size < 9. + let packed: Vec = vec![1, 255, 212, 82, 63, 57, 19, 134]; + let method_digest_unpacked = MethodDigest::unpack(packed).unwrap_err(); + let _expected_error = StorageError::new(KeyIdStorageErrorKind::SerializationError); + assert!(matches!(method_digest_unpacked, _expected_error)); + + // Vec size 0; + let packed: Vec = vec![]; + let method_digest_unpacked = MethodDigest::unpack(packed).unwrap_err(); + let _expected_error = StorageError::new(KeyIdStorageErrorKind::SerializationError); + assert!(matches!(method_digest_unpacked, _expected_error)); + } + + fn create_verification_method() -> VerificationMethod { + let keypair: KeyPair = KeyPair::new(KeyType::Ed25519).unwrap(); + let did: CoreDID = + CoreDID::parse(format!("did:example:{}", BaseEncoding::encode_base58(keypair.public()))).unwrap(); + VerificationMethod::new(did, KeyType::Ed25519, keypair.public(), "frag_1").unwrap() + } } diff --git a/identity_storage/src/key_id_storage/mod.rs b/identity_storage/src/key_id_storage/mod.rs index 11af300ca2..50087a5ef8 100644 --- a/identity_storage/src/key_id_storage/mod.rs +++ b/identity_storage/src/key_id_storage/mod.rs @@ -1,15 +1,16 @@ // Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +#[allow(clippy::module_inception)] +mod key_id_storage; mod key_id_storage_error; mod method_digest; -mod storage; #[cfg(feature = "memstore")] mod memstore; +pub use key_id_storage::*; pub use key_id_storage_error::*; #[cfg(feature = "memstore")] pub use memstore::*; pub use method_digest::*; -pub use storage::*; diff --git a/identity_storage/src/key_storage/jwk_storage.rs b/identity_storage/src/key_storage/jwk_storage.rs index 426b17214c..afcdd37af1 100644 --- a/identity_storage/src/key_storage/jwk_storage.rs +++ b/identity_storage/src/key_storage/jwk_storage.rs @@ -12,6 +12,7 @@ use identity_jose::jws::JwsAlgorithm; use super::key_gen::JwkGenOutput; +/// Result of key storage operations. pub type KeyStorageResult = Result; #[cfg(not(feature = "send-sync-storage"))] diff --git a/identity_storage/src/key_storage/key_storage_error.rs b/identity_storage/src/key_storage/key_storage_error.rs index 01982ba8d8..37b7502d92 100644 --- a/identity_storage/src/key_storage/key_storage_error.rs +++ b/identity_storage/src/key_storage/key_storage_error.rs @@ -6,6 +6,7 @@ use std::fmt::Display; use crate::error::StorageError; use crate::error::StorageErrorKind; +/// Error type for key storage operations. pub type KeyStorageError = StorageError; /// The cause of the failed key storage operation. From 874d15ec6002669ba4df243ffca7ba7b4ef89a45 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Tue, 7 Mar 2023 19:40:23 +0100 Subject: [PATCH 07/10] fix dependency version --- identity_storage/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/identity_storage/Cargo.toml b/identity_storage/Cargo.toml index 382e985b78..3003b8462f 100644 --- a/identity_storage/Cargo.toml +++ b/identity_storage/Cargo.toml @@ -15,7 +15,7 @@ description = "Abstractions over storage for cryptographic keys used in DID Docu async-trait = { version = "0.1.64", default-features = false } identity_core = { version = "=0.7.0-alpha.6", path = "../identity_core", default-features = false } identity_jose = { version = "=0.7.0-alpha.6", path = "../identity_jose", default-features = false } -identity_verification = { version = "=0.7.0-alpha.5", path = "../identity_verification", default_features = false } +identity_verification = { version = "=0.7.0-alpha.6", path = "../identity_verification", default_features = false } iota-crypto = { version = "0.15", default-features = false, features = ["blake2b", "ed25519", "random"], optional = true } rand = { version = "0.8.5", default-features = false, features = ["std"], optional = true } seahash = { version = "4.1.0", default_features = false } @@ -25,7 +25,7 @@ thiserror.workspace = true tokio = { version = "1.23.0", default-features = false, features = ["macros", "sync"], optional = true } [dev-dependencies] -identity_did = { version = "=0.7.0-alpha.5", path = "../identity_did", default-features = false } +identity_did = { version = "=0.7.0-alpha.6", path = "../identity_did", default-features = false } rand = { version = "0.8.5" } tokio = { version = "1.23.0", default-features = false, features = ["macros", "sync", "rt"] } From 0a7c4a1ab269b02c81d834951e201ab7fdc42e68 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Mon, 13 Mar 2023 09:38:48 +0100 Subject: [PATCH 08/10] fix typo --- identity_storage/src/key_id_storage/key_id_storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/identity_storage/src/key_id_storage/key_id_storage.rs b/identity_storage/src/key_id_storage/key_id_storage.rs index 60c77dff58..503a6a15a6 100644 --- a/identity_storage/src/key_id_storage/key_id_storage.rs +++ b/identity_storage/src/key_id_storage/key_id_storage.rs @@ -17,7 +17,7 @@ pub trait KeyIdStorage { /// Insert a [`KeyId`] into the [`KeyIdStorage`] under the given [`MethodDigest`]. /// If an entry for `key` already exists in the storage an error must be returned /// - /// immediately without altering the state the storage. + /// immediately without altering the state of the storage. async fn insert_key_id(&self, key: MethodDigest, value: KeyId) -> KeyIdStorageResult<()>; /// Obtain the [`KeyId`] associated with the given [`MethodDigest`]. From 90beb40d6d5e67b762f387e8908fc9ec8288be61 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Mon, 13 Mar 2023 10:05:07 +0100 Subject: [PATCH 09/10] fix clippy issue --- identity_storage/src/key_storage/memstore.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/identity_storage/src/key_storage/memstore.rs b/identity_storage/src/key_storage/memstore.rs index 162624a1cd..215cb5b47c 100644 --- a/identity_storage/src/key_storage/memstore.rs +++ b/identity_storage/src/key_storage/memstore.rs @@ -318,7 +318,7 @@ fn check_key_alg_compatibility(key_type: MemStoreKeyType, alg: JwsAlgorithm) -> match (key_type, alg) { (MemStoreKeyType::Ed25519, JwsAlgorithm::EdDSA) => Ok(()), (key_type, alg) => { - return Err( + Err( KeyStorageError::new(crate::key_storage::KeyStorageErrorKind::KeyAlgorithmMismatch) .with_custom_message(format!("`cannot use key type `{key_type}` with algorithm `{alg}`")), ) From 60af0b07bdc37added37166591190855f3cfcd10 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Mon, 13 Mar 2023 10:12:35 +0100 Subject: [PATCH 10/10] fmt --- identity_storage/src/key_storage/memstore.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/identity_storage/src/key_storage/memstore.rs b/identity_storage/src/key_storage/memstore.rs index 215cb5b47c..c0afad0d25 100644 --- a/identity_storage/src/key_storage/memstore.rs +++ b/identity_storage/src/key_storage/memstore.rs @@ -317,12 +317,10 @@ fn random_key_id() -> KeyId { fn check_key_alg_compatibility(key_type: MemStoreKeyType, alg: JwsAlgorithm) -> KeyStorageResult<()> { match (key_type, alg) { (MemStoreKeyType::Ed25519, JwsAlgorithm::EdDSA) => Ok(()), - (key_type, alg) => { - Err( - KeyStorageError::new(crate::key_storage::KeyStorageErrorKind::KeyAlgorithmMismatch) - .with_custom_message(format!("`cannot use key type `{key_type}` with algorithm `{alg}`")), - ) - } + (key_type, alg) => Err( + KeyStorageError::new(crate::key_storage::KeyStorageErrorKind::KeyAlgorithmMismatch) + .with_custom_message(format!("`cannot use key type `{key_type}` with algorithm `{alg}`")), + ), } }