Reorganize encyption related code

Some types used for encryption related tasks need to be used across more
internal crates than expected, so a few have been moved and renamed for
clarity.

* Rename the key_algorithms module in ruma-identifiers-validation to crypto_algorithms
* Move ruma_events::Algorithm to ruma-identifiers-validation and rename it EventEncryptionAlgorithm
* Move DeviceKeys from ruma-client-api to ruma-common
This commit is contained in:
Amanda Graven 2020-08-10 15:51:04 +02:00 committed by Jonas Platte
parent 585485831b
commit fdc15123b0
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
20 changed files with 138 additions and 131 deletions

View File

@ -2,8 +2,7 @@
use std::{collections::BTreeMap, fmt::Debug}; use std::{collections::BTreeMap, fmt::Debug};
use ruma_events::Algorithm; use ruma_identifiers::{DeviceKeyId, UserId};
use ruma_identifiers::{DeviceId, DeviceKeyId, UserId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod claim_keys; pub mod claim_keys;
@ -16,37 +15,6 @@ pub mod upload_signatures;
#[cfg(feature = "unstable-pre-spec")] #[cfg(feature = "unstable-pre-spec")]
pub mod upload_signing_keys; pub mod upload_signing_keys;
/// Identity keys for a device.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceKeys {
/// The ID of the user the device belongs to. Must match the user ID used when logging in.
pub user_id: UserId,
/// The ID of the device these keys belong to. Must match the device ID used when logging in.
pub device_id: Box<DeviceId>,
/// The encryption algorithms supported by this device.
pub algorithms: Vec<Algorithm>,
/// Public identity keys.
pub keys: BTreeMap<DeviceKeyId, String>,
/// Signatures for the device key object.
pub signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
/// Additional data added to the device key information by intermediate servers, and
/// not covered by the signatures.
#[serde(skip_serializing_if = "Option::is_none")]
pub unsigned: Option<UnsignedDeviceInfo>,
}
/// Additional data added to device key information by intermediate servers.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnsignedDeviceInfo {
/// The display name which the user set on the device.
pub device_display_name: Option<String>,
}
/// A key for the SignedCurve25519 algorithm /// A key for the SignedCurve25519 algorithm
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedKey { pub struct SignedKey {

View File

@ -3,12 +3,12 @@
use std::{collections::BTreeMap, time::Duration}; use std::{collections::BTreeMap, time::Duration};
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_common::encryption::DeviceKeys;
use ruma_identifiers::{DeviceId, UserId}; use ruma_identifiers::{DeviceId, UserId};
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
#[cfg(feature = "unstable-pre-spec")] #[cfg(feature = "unstable-pre-spec")]
use super::CrossSigningKey; use super::CrossSigningKey;
use super::DeviceKeys;
ruma_api! { ruma_api! {
metadata: { metadata: {

View File

@ -4,9 +4,10 @@ use std::collections::BTreeMap;
use js_int::UInt; use js_int::UInt;
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_common::encryption::DeviceKeys;
use ruma_identifiers::{DeviceKeyAlgorithm, DeviceKeyId}; use ruma_identifiers::{DeviceKeyAlgorithm, DeviceKeyId};
use super::{DeviceKeys, OneTimeKey}; use super::OneTimeKey;
ruma_api! { ruma_api! {
metadata: { metadata: {

View File

@ -0,0 +1,39 @@
//! Common types for [encryption] related tasks.
//!
//! [encryption](https://matrix.org/docs/spec/client_server/r0.6.1#id62)
use std::collections::BTreeMap;
use ruma_identifiers::{DeviceId, DeviceKeyId, EventEncryptionAlgorithm, UserId};
use serde::{Deserialize, Serialize};
/// Identity keys for a device.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceKeys {
/// The ID of the user the device belongs to. Must match the user ID used when logging in.
pub user_id: UserId,
/// The ID of the device these keys belong to. Must match the device ID used when logging in.
pub device_id: Box<DeviceId>,
/// The encryption algorithms supported by this device.
pub algorithms: Vec<EventEncryptionAlgorithm>,
/// Public identity keys.
pub keys: BTreeMap<DeviceKeyId, String>,
/// Signatures for the device key object.
pub signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
/// Additional data added to the device key information by intermediate servers, and
/// not covered by the signatures.
#[serde(skip_serializing_if = "Option::is_none")]
pub unsigned: Option<UnsignedDeviceInfo>,
}
/// Additional data added to device key information by intermediate servers.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnsignedDeviceInfo {
/// The display name which the user set on the device.
pub device_display_name: Option<String>,
}

View File

@ -2,6 +2,7 @@
#![warn(missing_docs, missing_debug_implementations)] #![warn(missing_docs, missing_debug_implementations)]
pub mod encryption;
pub mod presence; pub mod presence;
pub mod push; pub mod push;
mod raw; mod raw;

View File

@ -1,64 +0,0 @@
use std::fmt::{Display, Formatter, Result as FmtResult};
use serde::{Deserialize, Serialize};
/// An encryption algorithm to be used to encrypt messages sent to a room.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(from = "String", into = "String")]
pub enum Algorithm {
/// Olm version 1 using Curve25519, AES-256, and SHA-256.
OlmV1Curve25519AesSha2,
/// Megolm version 1 using AES-256 and SHA-256.
MegolmV1AesSha2,
/// Any algorithm that is not part of the specification.
Custom(String),
}
impl Display for Algorithm {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let algorithm_str = match *self {
Algorithm::OlmV1Curve25519AesSha2 => "m.olm.v1.curve25519-aes-sha2",
Algorithm::MegolmV1AesSha2 => "m.megolm.v1.aes-sha2",
Algorithm::Custom(ref algorithm) => algorithm,
};
write!(f, "{}", algorithm_str)
}
}
impl<T> From<T> for Algorithm
where
T: Into<String> + AsRef<str>,
{
fn from(s: T) -> Algorithm {
match s.as_ref() {
"m.olm.v1.curve25519-aes-sha2" => Algorithm::OlmV1Curve25519AesSha2,
"m.megolm.v1.aes-sha2" => Algorithm::MegolmV1AesSha2,
_ => Algorithm::Custom(s.into()),
}
}
}
impl From<Algorithm> for String {
fn from(algorithm: Algorithm) -> String {
algorithm.to_string()
}
}
#[cfg(test)]
mod tests {
use ruma_serde::test::serde_json_eq;
use serde_json::json;
use super::Algorithm;
#[test]
fn serialize_and_deserialize_from_display_form() {
serde_json_eq(Algorithm::MegolmV1AesSha2, json!("m.megolm.v1.aes-sha2"));
serde_json_eq(Algorithm::OlmV1Curve25519AesSha2, json!("m.olm.v1.curve25519-aes-sha2"));
serde_json_eq(Algorithm::Custom("io.ruma.test".into()), json!("io.ruma.test"));
}
}

View File

@ -1,10 +1,9 @@
//! Types for the *m.forwarded_room_key* event. //! Types for the *m.forwarded_room_key* event.
use ruma_events_macros::BasicEventContent; use ruma_events_macros::BasicEventContent;
use ruma_identifiers::RoomId; use ruma_identifiers::{EventEncryptionAlgorithm, RoomId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::Algorithm;
use crate::BasicEvent; use crate::BasicEvent;
/// This event type is used to forward keys for end-to-end encryption. /// This event type is used to forward keys for end-to-end encryption.
@ -17,7 +16,7 @@ pub type ForwardedRoomKeyEvent = BasicEvent<ForwardedRoomKeyEventContent>;
#[ruma_event(type = "m.forwarded_room_key")] #[ruma_event(type = "m.forwarded_room_key")]
pub struct ForwardedRoomKeyEventContent { pub struct ForwardedRoomKeyEventContent {
/// The encryption algorithm the key in this event is to be used with. /// The encryption algorithm the key in this event is to be used with.
pub algorithm: Algorithm, pub algorithm: EventEncryptionAlgorithm,
/// The room where the key is used. /// The room where the key is used.
pub room_id: RoomId, pub room_id: RoomId,

View File

@ -121,7 +121,7 @@ use std::fmt::Debug;
use js_int::Int; use js_int::Int;
use ruma_common::Raw; use ruma_common::Raw;
use ruma_identifiers::RoomId; use ruma_identifiers::{EventEncryptionAlgorithm, RoomId};
use serde::{ use serde::{
de::{self, IgnoredAny}, de::{self, IgnoredAny},
Deserialize, Serialize, Deserialize, Serialize,
@ -130,7 +130,6 @@ use serde_json::value::RawValue as RawJsonValue;
use self::room::redaction::{RedactionEvent, SyncRedactionEvent}; use self::room::redaction::{RedactionEvent, SyncRedactionEvent};
mod algorithm;
mod enums; mod enums;
mod error; mod error;
mod event_kinds; mod event_kinds;
@ -160,7 +159,6 @@ pub mod tag;
pub mod typing; pub mod typing;
pub use self::{ pub use self::{
algorithm::Algorithm,
enums::{ enums::{
AnyBasicEvent, AnyBasicEventContent, AnyEphemeralRoomEvent, AnyEphemeralRoomEventContent, AnyBasicEvent, AnyBasicEventContent, AnyEphemeralRoomEvent, AnyEphemeralRoomEventContent,
AnyEvent, AnyMessageEvent, AnyMessageEventContent, AnyPossiblyRedactedMessageEvent, AnyEvent, AnyMessageEvent, AnyMessageEventContent, AnyPossiblyRedactedMessageEvent,

View File

@ -4,7 +4,7 @@ use js_int::UInt;
use ruma_events_macros::StateEventContent; use ruma_events_macros::StateEventContent;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Algorithm, StateEvent}; use crate::{EventEncryptionAlgorithm, StateEvent};
/// Defines how messages sent in this room should be encrypted. /// Defines how messages sent in this room should be encrypted.
pub type EncryptionEvent = StateEvent<EncryptionEventContent>; pub type EncryptionEvent = StateEvent<EncryptionEventContent>;
@ -17,7 +17,7 @@ pub struct EncryptionEventContent {
/// The encryption algorithm to be used to encrypt messages sent in this room. /// The encryption algorithm to be used to encrypt messages sent in this room.
/// ///
/// Must be `m.megolm.v1.aes-sha2`. /// Must be `m.megolm.v1.aes-sha2`.
pub algorithm: Algorithm, pub algorithm: EventEncryptionAlgorithm,
/// How long the session should be used before changing it. /// How long the session should be used before changing it.
/// ///
@ -34,7 +34,7 @@ pub struct EncryptionEventContent {
impl EncryptionEventContent { impl EncryptionEventContent {
/// Creates a new `EncryptionEventContent` with the given algorithm. /// Creates a new `EncryptionEventContent` with the given algorithm.
pub fn new(algorithm: Algorithm) -> Self { pub fn new(algorithm: EventEncryptionAlgorithm) -> Self {
Self { algorithm, rotation_period_ms: None, rotation_period_msgs: None } Self { algorithm, rotation_period_ms: None, rotation_period_msgs: None }
} }
} }

View File

@ -1,10 +1,9 @@
//! Types for the *m.room_key* event. //! Types for the *m.room_key* event.
use ruma_events_macros::BasicEventContent; use ruma_events_macros::BasicEventContent;
use ruma_identifiers::RoomId; use ruma_identifiers::{EventEncryptionAlgorithm, RoomId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::Algorithm;
use crate::BasicEvent; use crate::BasicEvent;
/// This event type is used to exchange keys for end-to-end encryption. /// This event type is used to exchange keys for end-to-end encryption.
@ -19,7 +18,7 @@ pub struct RoomKeyEventContent {
/// The encryption algorithm the key in this event is to be used with. /// The encryption algorithm the key in this event is to be used with.
/// ///
/// Must be `m.megolm.v1.aes-sha2`. /// Must be `m.megolm.v1.aes-sha2`.
pub algorithm: Algorithm, pub algorithm: EventEncryptionAlgorithm,
/// The room where the key is used. /// The room where the key is used.
pub room_id: RoomId, pub room_id: RoomId,
@ -33,17 +32,17 @@ pub struct RoomKeyEventContent {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ruma_identifiers::room_id; use ruma_identifiers::{room_id, EventEncryptionAlgorithm};
use serde_json::{json, to_value as to_json_value}; use serde_json::{json, to_value as to_json_value};
use super::RoomKeyEventContent; use super::RoomKeyEventContent;
use crate::{Algorithm, BasicEvent}; use crate::BasicEvent;
#[test] #[test]
fn serialization() { fn serialization() {
let ev = BasicEvent { let ev = BasicEvent {
content: RoomKeyEventContent { content: RoomKeyEventContent {
algorithm: Algorithm::MegolmV1AesSha2, algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
room_id: room_id!("!testroomid:example.org"), room_id: room_id!("!testroomid:example.org"),
session_id: "SessId".into(), session_id: "SessId".into(),
session_key: "SessKey".into(), session_key: "SessKey".into(),

View File

@ -1,11 +1,10 @@
//! Types for the *m.room_key_request* event. //! Types for the *m.room_key_request* event.
use ruma_events_macros::BasicEventContent; use ruma_events_macros::BasicEventContent;
use ruma_identifiers::{DeviceId, RoomId}; use ruma_identifiers::{DeviceId, EventEncryptionAlgorithm, RoomId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use strum::{Display, EnumString}; use strum::{Display, EnumString};
use super::Algorithm;
use crate::BasicEvent; use crate::BasicEvent;
/// This event type is used to request keys for end-to-end encryption. /// This event type is used to request keys for end-to-end encryption.
@ -54,7 +53,7 @@ pub enum Action {
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RequestedKeyInfo { pub struct RequestedKeyInfo {
/// The encryption algorithm the requested key in this event is to be used with. /// The encryption algorithm the requested key in this event is to be used with.
pub algorithm: Algorithm, pub algorithm: EventEncryptionAlgorithm,
/// The room where the key is used. /// The room where the key is used.
pub room_id: RoomId, pub room_id: RoomId,

View File

@ -1,7 +1,5 @@
use ruma_events::{ use ruma_events::{room_key::RoomKeyEventContent, AnyToDeviceEventContent, ToDeviceEvent};
room_key::RoomKeyEventContent, Algorithm, AnyToDeviceEventContent, ToDeviceEvent, use ruma_identifiers::{room_id, user_id, EventEncryptionAlgorithm};
};
use ruma_identifiers::{room_id, user_id};
use serde_json::{json, to_value as to_json_value}; use serde_json::{json, to_value as to_json_value};
#[test] #[test]
@ -9,7 +7,7 @@ fn serialization() {
let ev = ToDeviceEvent { let ev = ToDeviceEvent {
sender: user_id!("@example:example.org"), sender: user_id!("@example:example.org"),
content: AnyToDeviceEventContent::RoomKey(RoomKeyEventContent { content: AnyToDeviceEventContent::RoomKey(RoomKeyEventContent {
algorithm: Algorithm::MegolmV1AesSha2, algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
room_id: room_id!("!testroomid:example.org"), room_id: room_id!("!testroomid:example.org"),
session_id: "SessId".into(), session_id: "SessId".into(),
session_key: "SessKey".into(), session_key: "SessKey".into(),

View File

@ -16,5 +16,7 @@ edition = "2018"
default = ["serde"] default = ["serde"]
[dependencies] [dependencies]
ruma-serde = { version = "0.2.3", path = "../ruma-serde" }
serde = { version = "1.0.114", optional = true, features = ["derive"] } serde = { version = "1.0.114", optional = true, features = ["derive"] }
serde_json = "1.0.57"
strum = { version = "0.19.2", features = ["derive"] } strum = { version = "0.19.2", features = ["derive"] }

View File

@ -1,6 +1,7 @@
//! Key algorithms used in Matrix spec. //! Key algorithms used in Matrix spec.
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt::{Display, Formatter, Result as FmtResult};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -65,9 +66,62 @@ impl TryFrom<String> for ServerKeyAlgorithm {
} }
} }
/// An encryption algorithm to be used to encrypt messages sent to a room.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(Deserialize, Serialize),
serde(from = "String", into = "String")
)]
#[non_exhaustive]
pub enum EventEncryptionAlgorithm {
/// Olm version 1 using Curve25519, AES-256, and SHA-256.
OlmV1Curve25519AesSha2,
/// Megolm version 1 using AES-256 and SHA-256.
MegolmV1AesSha2,
/// Any algorithm that is not part of the specification.
Custom(String),
}
impl Display for EventEncryptionAlgorithm {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let algorithm_str = match *self {
EventEncryptionAlgorithm::OlmV1Curve25519AesSha2 => "m.olm.v1.curve25519-aes-sha2",
EventEncryptionAlgorithm::MegolmV1AesSha2 => "m.megolm.v1.aes-sha2",
EventEncryptionAlgorithm::Custom(ref algorithm) => algorithm,
};
write!(f, "{}", algorithm_str)
}
}
impl<T> From<T> for EventEncryptionAlgorithm
where
T: Into<String> + AsRef<str>,
{
fn from(s: T) -> EventEncryptionAlgorithm {
match s.as_ref() {
"m.olm.v1.curve25519-aes-sha2" => EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
"m.megolm.v1.aes-sha2" => EventEncryptionAlgorithm::MegolmV1AesSha2,
_ => EventEncryptionAlgorithm::Custom(s.into()),
}
}
}
impl From<EventEncryptionAlgorithm> for String {
fn from(algorithm: EventEncryptionAlgorithm) -> String {
algorithm.to_string()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{DeviceKeyAlgorithm, ServerKeyAlgorithm}; use ruma_serde::test::serde_json_eq;
use serde_json::json;
use super::{DeviceKeyAlgorithm, EventEncryptionAlgorithm, ServerKeyAlgorithm};
#[test] #[test]
fn parse_device_key_algorithm() { fn parse_device_key_algorithm() {
@ -80,4 +134,17 @@ mod tests {
fn parse_server_key_algorithm() { fn parse_server_key_algorithm() {
assert_eq!("ed25519".parse(), Ok(ServerKeyAlgorithm::Ed25519)); assert_eq!("ed25519".parse(), Ok(ServerKeyAlgorithm::Ed25519));
} }
#[test]
fn event_encryption_algorithm_serde() {
serde_json_eq(EventEncryptionAlgorithm::MegolmV1AesSha2, json!("m.megolm.v1.aes-sha2"));
serde_json_eq(
EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
json!("m.olm.v1.curve25519-aes-sha2"),
);
serde_json_eq(
EventEncryptionAlgorithm::Custom("io.ruma.test".into()),
json!("io.ruma.test"),
);
}
} }

View File

@ -1,6 +1,6 @@
use std::{num::NonZeroU8, str::FromStr}; use std::{num::NonZeroU8, str::FromStr};
use crate::{key_algorithms::DeviceKeyAlgorithm, Error}; use crate::{crypto_algorithms::DeviceKeyAlgorithm, Error};
pub fn validate(s: &str) -> Result<NonZeroU8, Error> { pub fn validate(s: &str) -> Result<NonZeroU8, Error> {
let colon_idx = NonZeroU8::new(s.find(':').ok_or(Error::MissingDeviceKeyDelimiter)? as u8) let colon_idx = NonZeroU8::new(s.find(':').ok_or(Error::MissingDeviceKeyDelimiter)? as u8)

View File

@ -1,7 +1,7 @@
pub mod crypto_algorithms;
pub mod device_key_id; pub mod device_key_id;
pub mod error; pub mod error;
pub mod event_id; pub mod event_id;
pub mod key_algorithms;
pub mod room_alias_id; pub mod room_alias_id;
pub mod room_id; pub mod room_id;
pub mod room_id_or_alias_id; pub mod room_id_or_alias_id;

View File

@ -1,6 +1,6 @@
use std::{num::NonZeroU8, str::FromStr}; use std::{num::NonZeroU8, str::FromStr};
use crate::{key_algorithms::ServerKeyAlgorithm, Error}; use crate::{crypto_algorithms::ServerKeyAlgorithm, Error};
pub fn validate(s: &str) -> Result<NonZeroU8, Error> { pub fn validate(s: &str) -> Result<NonZeroU8, Error> {
let colon_idx = NonZeroU8::new(s.find(':').ok_or(Error::MissingServerKeyDelimiter)? as u8) let colon_idx = NonZeroU8::new(s.find(':').ok_or(Error::MissingServerKeyDelimiter)? as u8)

View File

@ -2,7 +2,7 @@
use std::{convert::TryInto, num::NonZeroU8, str::FromStr}; use std::{convert::TryInto, num::NonZeroU8, str::FromStr};
use ruma_identifiers_validation::{key_algorithms::DeviceKeyAlgorithm, Error}; use ruma_identifiers_validation::{crypto_algorithms::DeviceKeyAlgorithm, Error};
use crate::DeviceId; use crate::DeviceId;
@ -56,7 +56,7 @@ common_impls!(DeviceKeyId, try_from, "Device key ID with algorithm and device ID
mod test { mod test {
use std::convert::TryFrom; use std::convert::TryFrom;
use ruma_identifiers_validation::{key_algorithms::DeviceKeyAlgorithm, Error}; use ruma_identifiers_validation::{crypto_algorithms::DeviceKeyAlgorithm, Error};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

View File

@ -22,8 +22,8 @@ pub use crate::{
}; };
#[doc(inline)] #[doc(inline)]
pub use ruma_identifiers_validation::{ pub use ruma_identifiers_validation::{
crypto_algorithms::{DeviceKeyAlgorithm, EventEncryptionAlgorithm, ServerKeyAlgorithm},
error::Error, error::Error,
key_algorithms::{DeviceKeyAlgorithm, ServerKeyAlgorithm},
}; };
#[macro_use] #[macro_use]

View File

@ -2,7 +2,7 @@
use std::{convert::TryInto, num::NonZeroU8, str::FromStr}; use std::{convert::TryInto, num::NonZeroU8, str::FromStr};
use ruma_identifiers_validation::{key_algorithms::ServerKeyAlgorithm, Error}; use ruma_identifiers_validation::{crypto_algorithms::ServerKeyAlgorithm, Error};
/// Key identifiers used for homeserver signing keys. /// Key identifiers used for homeserver signing keys.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -59,7 +59,7 @@ mod tests {
use crate::{Error, ServerKeyId}; use crate::{Error, ServerKeyId};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use ruma_identifiers_validation::key_algorithms::ServerKeyAlgorithm; use ruma_identifiers_validation::crypto_algorithms::ServerKeyAlgorithm;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[test] #[test]