Move code examples onto relevant functions/types and rewrite the crate
documentation to be a more general overview.
This commit is contained in:
		
							parent
							
								
									bca31bfbd4
								
							
						
					
					
						commit
						f1d9eba728
					
				
							
								
								
									
										189
									
								
								src/functions.rs
									
									
									
									
									
								
							
							
						
						
									
										189
									
								
								src/functions.rs
									
									
									
									
									
								
							| @ -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>, | ||||
|  | ||||
							
								
								
									
										284
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										284
									
								
								src/lib.rs
									
									
									
									
									
								
							| @ -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, | ||||
|  | ||||
| @ -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.
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user