Move code examples onto relevant functions/types and rewrite the crate

documentation to be a more general overview.
This commit is contained in:
Jimmy Cuadra 2019-07-10 01:04:38 -07:00
parent bca31bfbd4
commit f1d9eba728
3 changed files with 271 additions and 251 deletions

View File

@ -71,6 +71,45 @@ static REFERENCE_HASH_FIELDS_TO_REMOVE: &[&str] = &["age_ts", "signatures", "uns
/// * `value` is not a JSON object.
/// * `value` contains a field called `signatures` that is not a JSON object.
/// * `server_name` cannot be parsed as a valid host.
///
/// # Examples
///
/// A homeserver signs JSON with a key pair:
///
/// ```rust
/// use ruma_signatures::KeyPair as _;
///
/// const PUBLIC_KEY: &str = "XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
/// const PRIVATE_KEY: &str = "YJDBA9Xnr2sVqXD9Vj7XVUnmFZcZrlw8Md7kMW+3XA0";
///
/// let public_key = base64::decode_config(&PUBLIC_KEY, base64::STANDARD_NO_PAD).unwrap();
/// let private_key = base64::decode_config(&PRIVATE_KEY, base64::STANDARD_NO_PAD).unwrap();
///
/// // Create an Ed25519 key pair.
/// let key_pair = ruma_signatures::Ed25519KeyPair::new(
/// &public_key,
/// &private_key,
/// "1".to_string(), // The "version" of the key.
/// ).unwrap();
///
/// // Deserialize some JSON.
/// let mut value = serde_json::from_str("{}").unwrap();
///
/// // Sign the JSON with the key pair.
/// assert!(ruma_signatures::sign_json("example.com", &key_pair, &mut value).is_ok());
/// ```
///
/// This will modify the JSON from an empty object to a structure like this:
///
/// ```json
/// {
/// "signatures": {
/// "example.com": {
/// "ed25519:1": "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"
/// }
/// }
/// }
/// ```
pub fn sign_json<K>(server_name: &str, key_pair: &K, value: &mut Value) -> Result<(), Error>
where
K: KeyPair,
@ -148,6 +187,30 @@ pub fn to_canonical_json(value: &Value) -> Result<String, Error> {
/// # Errors
///
/// Returns an error if verification fails.
///
/// # Examples
///
/// ```rust
/// const PUBLIC_KEY: &str = "XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
/// const SIGNATURE_BYTES: &str =
/// "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ";
///
/// // Decode the public key used to generate the signature into raw bytes.
/// let public_key = base64::decode_config(&PUBLIC_KEY, base64::STANDARD_NO_PAD).unwrap();
///
/// // Create a `Signature` from the raw bytes of the signature.
/// let signature_bytes = base64::decode_config(&SIGNATURE_BYTES, base64::STANDARD_NO_PAD).unwrap();
/// let signature = ruma_signatures::Signature::new("ed25519:1", &signature_bytes).unwrap();
///
/// // Deserialize the signed JSON.
/// let value = serde_json::from_str("{}").unwrap();
///
/// // Create the verifier for the Ed25519 algorithm.
/// let verifier = ruma_signatures::Ed25519Verifier;
///
/// // Verify the signature.
/// assert!(ruma_signatures::verify_json(&verifier, &public_key, &signature, &value).is_ok());
/// ```
pub fn verify_json<V>(
verifier: &V,
public_key: &[u8],
@ -230,6 +293,77 @@ pub fn reference_hash(value: &Value) -> Result<String, Error> {
/// * `value` contains a field called `signatures` that is not a JSON object.
/// * `value` is missing the `type` field or the field is not a JSON string.
/// * `server_name` cannot be parsed as a valid host.
///
/// # Examples
///
/// ```rust
/// use ruma_signatures::KeyPair as _;
///
/// const PUBLIC_KEY: &str = "XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
/// const PRIVATE_KEY: &str = "YJDBA9Xnr2sVqXD9Vj7XVUnmFZcZrlw8Md7kMW+3XA0";
///
/// let public_key = base64::decode_config(&PUBLIC_KEY, base64::STANDARD_NO_PAD).unwrap();
/// let private_key = base64::decode_config(&PRIVATE_KEY, base64::STANDARD_NO_PAD).unwrap();
///
/// // Create an Ed25519 key pair.
/// let key_pair = ruma_signatures::Ed25519KeyPair::new(
/// &public_key,
/// &private_key,
/// "1".to_string(), // The "version" of the key.
/// ).unwrap();
///
/// // Deserialize an event from JSON.
/// let mut value = serde_json::from_str(
/// r#"{
/// "room_id": "!x:domain",
/// "sender": "@a:domain",
/// "origin": "domain",
/// "origin_server_ts": 1000000,
/// "signatures": {},
/// "hashes": {},
/// "type": "X",
/// "content": {},
/// "prev_events": [],
/// "auth_events": [],
/// "depth": 3,
/// "unsigned": {
/// "age_ts": 1000000
/// }
/// }"#
/// ).unwrap();
///
/// // Hash and sign the JSON with the key pair.
/// assert!(ruma_signatures::hash_and_sign_event("example.com", &key_pair, &mut value).is_ok());
/// ```
///
/// This will modify the JSON from the structure shown to a structure like this:
///
/// ```json
/// {
/// "auth_events": [],
/// "content": {},
/// "depth": 3,
/// "hashes": {
/// "sha256": "5jM4wQpv6lnBo7CLIghJuHdW+s2CMBJPUOGOC89ncos"
/// },
/// "origin": "domain",
/// "origin_server_ts": 1000000,
/// "prev_events": [],
/// "room_id": "!x:domain",
/// "sender": "@a:domain",
/// "signatures": {
/// "domain": {
/// "ed25519:1": "KxwGjPSDEtvnFgU00fwFz+l6d2pJM6XBIaMEn81SXPTRl16AqLAYqfIReFGZlHi5KLjAWbOoMszkwsQma+lYAg"
/// }
/// },
/// "type": "X",
/// "unsigned": {
/// "age_ts": 1000000
/// }
/// }
/// ```
///
/// Notice the addition of `hashes` and `signatures`.
pub fn hash_and_sign_event<K>(
server_name: &str,
key_pair: &K,
@ -272,18 +406,69 @@ where
/// Uses a set of public keys to verify a signed JSON representation of an event.
///
/// Some room versions may require signatures from multiple homeservers, so this function takes a
/// map of servers to sets of public keys. For each homeserver present in the map, this function
/// map from servers to sets of public keys. For each homeserver present in the map, this function
/// will require a valid signature. All known public keys for a homeserver should be provided. The
/// first one found on the given event will be used.
///
/// # Parameters
///
/// * verifier: A `Verifier` appropriate for the digital signature algorithm that was used.
/// * verify_key_map: A map of server names to a map of key identifiers to public keys. Server
/// * verify_key_map: A map from server names to a map from key identifiers to public keys. Server
/// names are the hostname or IP of a homeserver (e.g. "example.com") for which a signature must be
/// verified. Key identifiers for each server (e.g. "ed25519:1") then map to their respective public
/// keys.
/// * value: The `serde_json::Value` (JSON value) of the event that was signed.
///
/// # Examples
///
/// ```rust
/// use std::collections::HashMap;
///
/// const PUBLIC_KEY: &str = "XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
///
/// // Decode the public key used to generate the signature into raw bytes.
/// let public_key = base64::decode_config(&PUBLIC_KEY, base64::STANDARD_NO_PAD).unwrap();
///
/// // Create a map from key ID to public key.
/// let mut example_server_keys = HashMap::new();
/// example_server_keys.insert("ed25519:1", public_key.as_slice());
///
/// // Insert the public keys into a map keyed by server name.
/// let mut verify_key_map = HashMap::new();
/// verify_key_map.insert("domain", example_server_keys);
///
/// // Deserialize an event from JSON.
/// let value = serde_json::from_str(
/// r#"{
/// "auth_events": [],
/// "content": {},
/// "depth": 3,
/// "hashes": {
/// "sha256": "5jM4wQpv6lnBo7CLIghJuHdW+s2CMBJPUOGOC89ncos"
/// },
/// "origin": "domain",
/// "origin_server_ts": 1000000,
/// "prev_events": [],
/// "room_id": "!x:domain",
/// "sender": "@a:domain",
/// "signatures": {
/// "domain": {
/// "ed25519:1": "KxwGjPSDEtvnFgU00fwFz+l6d2pJM6XBIaMEn81SXPTRl16AqLAYqfIReFGZlHi5KLjAWbOoMszkwsQma+lYAg"
/// }
/// },
/// "type": "X",
/// "unsigned": {
/// "age_ts": 1000000
/// }
/// }"#
/// ).unwrap();
///
/// // Create the verifier for the Ed25519 algorithm.
/// let verifier = ruma_signatures::Ed25519Verifier;
///
/// // Verify at least one signature for each server in `verify_key_map`.
/// assert!(ruma_signatures::verify_event(&verifier, verify_key_map, &value).is_ok());
/// ```
pub fn verify_event<V, S>(
verifier: &V,
verify_key_map: HashMap<&str, HashMap<&str, &[u8], S>, S>,

View File

@ -3,218 +3,30 @@
//!
//! Digital signatures are used by Matrix homeservers to verify the authenticity of events in the
//! Matrix system, as well as requests between homeservers for federation. Each homeserver has one
//! or more signing key pairs which it uses to sign all events and federation requests. Matrix
//! clients and other Matrix homeservers can ask the homeserver for its public keys and use those
//! keys to verify the signed data.
//! or more signing key pairs (sometimes referred to as "verify keys") which it uses to sign all
//! events and federation requests. Matrix clients and other Matrix homeservers can ask the
//! homeserver for its public keys and use those keys to verify the signed data.
//!
//! Each signing key pair has an identifier, which consists of the name of the digital signature
//! algorithm it uses and a "version" string, separated by a colon. The version is an arbitrary
//! identifier used to distinguish key pairs using the same algorithm from the same homeserver.
//!
//! In JSON representations, signatures and hashes appear as Base64-encoded strings, using the
//! Arbitrary JSON objects can be signed as well as JSON representations of Matrix events. In both
//! cases, the signatures are stored within the JSON object itself under a `signatures` key. Events
//! are also required to contain hashes of their content, which are similarly stored within the
//! hashed JSON object under a `hashes` key.
//!
//! In JSON representations, both signatures and hashes appear as Base64-encoded strings, using the
//! standard character set, without padding.
//!
//! # Signing JSON
//! # Signatures, maps, and sets
//!
//! A homeserver signs JSON with a key pair:
//! An individual signature is represented in ruma-signatures by the `Signature` type. This type
//! encapsulates the raw bytes of the signature, the identifier for the signing key used, and the
//! algorithm used to create the signature.
//!
//! ```rust
//! use ruma_signatures::KeyPair as _;
//!
//! const PUBLIC_KEY: &str = "XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
//! const PRIVATE_KEY: &str = "YJDBA9Xnr2sVqXD9Vj7XVUnmFZcZrlw8Md7kMW+3XA0";
//!
//! let public_key = base64::decode_config(&PUBLIC_KEY, base64::STANDARD_NO_PAD).unwrap();
//! let private_key = base64::decode_config(&PRIVATE_KEY, base64::STANDARD_NO_PAD).unwrap();
//!
//! // Create an Ed25519 key pair.
//! let key_pair = ruma_signatures::Ed25519KeyPair::new(
//! &public_key,
//! &private_key,
//! "1".to_string(), // The "version" of the key.
//! ).unwrap();
//!
//! // Deserialize some JSON.
//! let mut value = serde_json::from_str("{}").unwrap();
//!
//! // Sign the JSON with the key pair.
//! assert!(ruma_signatures::sign_json("example.com", &key_pair, &mut value).is_ok());
//! ```
//!
//! This will modify the JSON from an empty object to a structure like this:
//!
//! ```json
//! {
//! "signatures": {
//! "example.com": {
//! "ed25519:1": "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"
//! }
//! }
//! }
//! ```
//!
//! # Hashing and signing Matrix events
//!
//! Signing an event uses a more involved process than signing arbitrary JSON because events can be
//! redacted and signatures need to remain valid even if data is removed from an event later.
//! Homeservers are required to generate hashes of event contents and sign events before exchanging
//! them with other homeservers. Although the algorithm for hashing and signing an event is more
//! complicated than for signing arbitrary JSON, the interface to a user of ruma-signatures is the
//! same:
//!
//! ```rust
//! use ruma_signatures::KeyPair as _;
//!
//! const PUBLIC_KEY: &str = "XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
//! const PRIVATE_KEY: &str = "YJDBA9Xnr2sVqXD9Vj7XVUnmFZcZrlw8Md7kMW+3XA0";
//!
//! let public_key = base64::decode_config(&PUBLIC_KEY, base64::STANDARD_NO_PAD).unwrap();
//! let private_key = base64::decode_config(&PRIVATE_KEY, base64::STANDARD_NO_PAD).unwrap();
//!
//! // Create an Ed25519 key pair.
//! let key_pair = ruma_signatures::Ed25519KeyPair::new(
//! &public_key,
//! &private_key,
//! "1".to_string(), // The "version" of the key.
//! ).unwrap();
//!
//! // Deserialize an event from JSON.
//! let mut value = serde_json::from_str(
//! r#"{
//! "room_id": "!x:domain",
//! "sender": "@a:domain",
//! "origin": "domain",
//! "origin_server_ts": 1000000,
//! "signatures": {},
//! "hashes": {},
//! "type": "X",
//! "content": {},
//! "prev_events": [],
//! "auth_events": [],
//! "depth": 3,
//! "unsigned": {
//! "age_ts": 1000000
//! }
//! }"#
//! ).unwrap();
//!
//! // Hash and sign the JSON with the key pair.
//! assert!(ruma_signatures::hash_and_sign_event("example.com", &key_pair, &mut value).is_ok());
//! ```
//!
//! This will modify the JSON from the structure shown to a structure like this:
//!
//! ```json
//! {
//! "auth_events": [],
//! "content": {},
//! "depth": 3,
//! "hashes": {
//! "sha256": "5jM4wQpv6lnBo7CLIghJuHdW+s2CMBJPUOGOC89ncos"
//! },
//! "origin": "domain",
//! "origin_server_ts": 1000000,
//! "prev_events": [],
//! "room_id": "!x:domain",
//! "sender": "@a:domain",
//! "signatures": {
//! "domain": {
//! "ed25519:1": "KxwGjPSDEtvnFgU00fwFz+l6d2pJM6XBIaMEn81SXPTRl16AqLAYqfIReFGZlHi5KLjAWbOoMszkwsQma+lYAg"
//! }
//! },
//! "type": "X",
//! "unsigned": {
//! "age_ts": 1000000
//! }
//! }
//! ```
//!
//! Notice the addition of `hashes` and `signatures`.
//!
//! # Verifying signatures
//!
//! A client application or another homeserver can verify a signature on arbitrary JSON:
//!
//! ```rust
//! const PUBLIC_KEY: &str = "XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
//! const SIGNATURE_BYTES: &str =
//! "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ";
//!
//! // Decode the public key used to generate the signature into raw bytes.
//! let public_key = base64::decode_config(&PUBLIC_KEY, base64::STANDARD_NO_PAD).unwrap();
//!
//! // Create a `Signature` from the raw bytes of the signature.
//! let signature_bytes = base64::decode_config(&SIGNATURE_BYTES, base64::STANDARD_NO_PAD).unwrap();
//! let signature = ruma_signatures::Signature::new("ed25519:1", &signature_bytes).unwrap();
//!
//! // Deserialize the signed JSON.
//! let value = serde_json::from_str("{}").unwrap();
//!
//! // Create the verifier for the Ed25519 algorithm.
//! let verifier = ruma_signatures::Ed25519Verifier;
//!
//! // Verify the signature.
//! assert!(ruma_signatures::verify_json(&verifier, &public_key, &signature, &value).is_ok());
//! ```
//!
//! Verifying the signatures on a Matrix event are slightly different:
//!
//! ```rust
//! use std::collections::HashMap;
//!
//! const PUBLIC_KEY: &str = "XGX0JRS2Af3be3knz2fBiRbApjm2Dh61gXDJA8kcJNI";
//!
//! // Decode the public key used to generate the signature into raw bytes.
//! let public_key = base64::decode_config(&PUBLIC_KEY, base64::STANDARD_NO_PAD).unwrap();
//!
//! // Create a map of key ID to public key.
//! let mut example_server_keys = HashMap::new();
//! example_server_keys.insert("ed25519:1", public_key.as_slice());
//!
//! // Insert the public keys into a map keyed by server name.
//! let mut verify_key_map = HashMap::new();
//! verify_key_map.insert("domain", example_server_keys);
//!
//! // Deserialize an event from JSON.
//! let value = serde_json::from_str(
//! r#"{
//! "auth_events": [],
//! "content": {},
//! "depth": 3,
//! "hashes": {
//! "sha256": "5jM4wQpv6lnBo7CLIghJuHdW+s2CMBJPUOGOC89ncos"
//! },
//! "origin": "domain",
//! "origin_server_ts": 1000000,
//! "prev_events": [],
//! "room_id": "!x:domain",
//! "sender": "@a:domain",
//! "signatures": {
//! "domain": {
//! "ed25519:1": "KxwGjPSDEtvnFgU00fwFz+l6d2pJM6XBIaMEn81SXPTRl16AqLAYqfIReFGZlHi5KLjAWbOoMszkwsQma+lYAg"
//! }
//! },
//! "type": "X",
//! "unsigned": {
//! "age_ts": 1000000
//! }
//! }"#
//! ).unwrap();
//!
//! // Create the verifier for the Ed25519 algorithm.
//! let verifier = ruma_signatures::Ed25519Verifier;
//!
//! // Verify at least one signature for each server in `verify_key_map`.
//! assert!(ruma_signatures::verify_event(&verifier, verify_key_map, &value).is_ok());
//! ```
//!
//! See the documentation for `verify_event` for details on what verification entails and the
//! `verify_key_map` parameter.
//!
//! # Signature sets and maps
//!
//! Signatures that a homeserver has added to an event are stored in a JSON object under the
//! "signatures" key in the event's JSON representation:
//! As mentioned, signatures that a homeserver has added to an event are stored in a JSON object
//! under the `signatures` key in the event's JSON representation:
//!
//! ```json
//! {
@ -228,56 +40,34 @@
//! }
//! ```
//!
//! The keys inside the "signatures" object are the hostnames of homeservers that have added
//! signatures. Within each of those objects are a set of signatures, keyed by the signing key
//! pair's identifier.
//! The value of the the `signatures` key is represented in ruma-signatures by the `SignatureMap`
//! type. This type maps the name of a homeserver to a set of its signatures for the containing
//! data. The set of signatures for each homeserver (which appears as a map from key ID to signature
//! in the JSON representation) is represented in ruma-signatures by the `SignatureSet` type. Both
//! `SignatureMap`s and `SignatureSet`s can be serialized and deserialized with
//! [https://serde.rs/](Serde).
//!
//! This inner object can be created by serializing a `SignatureSet`:
//! # Signing and hashing
//!
//! ```rust
//! const SIGNATURE_BYTES: &str =
//! "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ";
//! To sign an arbitrary JSON object, use the `sign_json` function. See the documentation of this
//! function for more details and a full example of use.
//!
//! // Create a `Signature` from the raw bytes of the signature.
//! let signature_bytes = base64::decode_config(&SIGNATURE_BYTES, base64::STANDARD_NO_PAD).unwrap();
//! let signature = ruma_signatures::Signature::new("ed25519:1", &signature_bytes).unwrap();
//! Signing an event uses a more complicated process than signing arbitrary JSON, because events can
//! be redacted, and signatures need to remain valid even if data is removed from an event later.
//! Homeservers are required to generate hashes of event contents as well as signing events before
//! exchanging them with other homeservers. Although the algorithm for hashing and signing an event
//! is more complicated than for signing arbitrary JSON, the interface to a user of ruma-signatures
//! is the same. To hash and sign an event, use the `hash_and_sign_event` function. See the
//! documentation of this function for more details and a full example of use.
//!
//! // Create a `SignatureSet` and insert the signature into it.
//! let mut signature_set = ruma_signatures::SignatureSet::new();
//! signature_set.insert(signature);
//! # Verifying signatures and hashes
//!
//! // Serialize the set to JSON.
//! assert!(serde_json::to_string(&signature_set).is_ok());
//! ```
//! When a homeserver receives data from another homeserver via the federation, it's necessary to
//! verify the authenticity and integrity of the data by verifying their signatures.
//!
//! This code produces the object under the "example.com" key in the preceeding JSON. Similarly,
//! a `SignatureSet` can be produced by deserializing JSON that follows this form.
//!
//! The outer object (the map of server names to signature sets) is a `SignatureMap` value and
//! created like this:
//!
//! ```rust
//! const SIGNATURE_BYTES: &str =
//! "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ";
//!
//! // Create a `Signature` from the raw bytes of the signature.
//! let signature_bytes = base64::decode_config(&SIGNATURE_BYTES, base64::STANDARD_NO_PAD).unwrap();
//! let signature = ruma_signatures::Signature::new("ed25519:1", &signature_bytes).unwrap();
//!
//! // Create a `SignatureSet` and insert the signature into it.
//! let mut signature_set = ruma_signatures::SignatureSet::new();
//! signature_set.insert(signature);
//!
//! // Create a `SignatureMap` and insert the set into it, keyed by the homeserver name.
//! let mut signature_map = ruma_signatures::SignatureMap::new();
//! signature_map.insert("example.com", signature_set).unwrap();
//!
//! // Serialize the map to JSON.
//! assert!(serde_json::to_string(&signature_map).is_ok());
//! ```
//!
//! Just like the `SignatureSet` itself, the `SignatureMap` value can also be deserialized from
//! JSON.
//! To verify a signature on arbitrary JSON, use the `verify_json` function. To verify the
//! signatures and hashes on an event, use the `verify_event` function. See the documentation for
//! these respective functions for more details and full examples of use.
#![deny(
missing_copy_implementations,

View File

@ -88,10 +88,35 @@ impl Signature {
}
}
/// A map of server names to sets of digital signatures created by that server.
/// A map from server names to sets of digital signatures created by that server.
///
/// # Examples
///
/// Creating and serializing a `SignatureMap`:
///
/// ```rust
/// const SIGNATURE_BYTES: &str =
/// "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ";
///
/// // Create a `Signature` from the raw bytes of the signature.
/// let signature_bytes = base64::decode_config(&SIGNATURE_BYTES, base64::STANDARD_NO_PAD).unwrap();
/// let signature = ruma_signatures::Signature::new("ed25519:1", &signature_bytes).unwrap();
///
/// // Create a `SignatureSet` and insert the signature into it.
/// let mut signature_set = ruma_signatures::SignatureSet::new();
/// signature_set.insert(signature);
///
/// // Create a `SignatureMap` and insert the set into it, keyed by the homeserver name.
/// let mut signature_map = ruma_signatures::SignatureMap::new();
/// signature_map.insert("example.com", signature_set).unwrap();
///
/// // Serialize the map to JSON.
/// assert!(serde_json::to_string(&signature_map).is_ok());
/// ```
///
#[derive(Clone, Debug, Default, PartialEq)]
pub struct SignatureMap {
/// A map of homeservers to sets of signatures for the homeserver.
/// A map from homeservers to sets of signatures for the homeserver.
map: HashMap<Host, SignatureSet>,
}
@ -253,6 +278,26 @@ impl<'de> Visitor<'de> for SignatureMapVisitor {
}
/// A set of digital signatures created by a single homeserver.
///
/// # Examples
///
/// Creating and serializing a `SignatureSet`:
///
/// ```rust
/// const SIGNATURE_BYTES: &str =
/// "K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ";
///
/// // Create a `Signature` from the raw bytes of the signature.
/// let signature_bytes = base64::decode_config(&SIGNATURE_BYTES, base64::STANDARD_NO_PAD).unwrap();
/// let signature = ruma_signatures::Signature::new("ed25519:1", &signature_bytes).unwrap();
///
/// // Create a `SignatureSet` and insert the signature into it.
/// let mut signature_set = ruma_signatures::SignatureSet::new();
/// signature_set.insert(signature);
///
/// // Serialize the set to JSON.
/// assert!(serde_json::to_string(&signature_set).is_ok());
/// ```
#[derive(Clone, Debug, Default, PartialEq)]
pub struct SignatureSet {
/// A set of signatures for a homeserver.