Skip to main content

matrix_sdk_crypto/types/signatures/
signature.rs

1/*
2Copyright 2022-2026 The Matrix.org Foundation C.I.C.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16use as_variant::as_variant;
17use ruma::DeviceKeyAlgorithm;
18use vodozemac::Ed25519Signature;
19
20use crate::types::InvalidSignature;
21
22/// Represents a potentially decoded signature (but *not* a validated one).
23///
24/// There are two important cases here:
25///
26/// 1. If the claimed algorithm is supported *and* the payload has an expected
27///    format, the signature will be represent by the enum variant corresponding
28///    to that algorithm. For example, decodable Ed25519 signatures are
29///    represented as `Ed25519(...)`.
30/// 2. If the claimed algorithm is unsupported, the signature is represented as
31///    `Other(...)`.
32#[derive(Clone, Debug, PartialEq, Eq)]
33pub enum Signature {
34    /// A Ed25519 digital signature.
35    Ed25519(Ed25519Signature),
36    /// A digital signature in an unsupported algorithm. The raw signature bytes
37    /// are represented as a base64-encoded string.
38    Other(String),
39}
40
41impl Signature {
42    /// Get the Ed25519 signature, if this is one.
43    pub fn ed25519(&self) -> Option<Ed25519Signature> {
44        as_variant!(self, Self::Ed25519).copied()
45    }
46
47    /// Decode a signature from the Base64-encoded format used in Matrix
48    /// `signatures` maps.
49    pub fn from_base64(algorithm: DeviceKeyAlgorithm, s: String) -> Result<Self, InvalidSignature> {
50        match algorithm {
51            DeviceKeyAlgorithm::Ed25519 => Ed25519Signature::from_base64(&s)
52                .map(|s| s.into())
53                .map_err(|_| InvalidSignature { source: s }),
54            _ => Ok(Signature::Other(s)),
55        }
56    }
57
58    /// Convert the signature to a base64 encoded string.
59    pub fn to_base64(&self) -> String {
60        match self {
61            Signature::Ed25519(s) => s.to_base64(),
62            Signature::Other(s) => s.to_owned(),
63        }
64    }
65}
66
67impl From<Ed25519Signature> for Signature {
68    fn from(signature: Ed25519Signature) -> Self {
69        Self::Ed25519(signature)
70    }
71}
72
73#[cfg(test)]
74mod test {
75    use super::*;
76
77    #[test]
78    fn roundtrip_ed25519_signature() {
79        const BASE64_SIG: &str = "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ";
80
81        let parsed = Signature::from_base64(DeviceKeyAlgorithm::Ed25519, BASE64_SIG.to_owned())
82            .expect("Failed to parse");
83
84        let ed25519 = parsed.ed25519().expect("Not parsed as Ed25519");
85        assert_eq!(ed25519.to_base64(), BASE64_SIG);
86
87        let encoded = parsed.to_base64();
88        assert_eq!(encoded, BASE64_SIG)
89    }
90
91    #[test]
92    fn parse_invalid_ed25519_signature() {
93        const BASE64_SIG: &str = "XXXX";
94
95        let parsed = Signature::from_base64(DeviceKeyAlgorithm::Ed25519, BASE64_SIG.to_owned())
96            .expect_err("Expected an invalid signature");
97        assert_eq!(parsed.source, BASE64_SIG);
98    }
99
100    #[test]
101    fn roundtrip_other_signature() {
102        const TEXT: &str = "abcd";
103
104        let parsed = Signature::from_base64(DeviceKeyAlgorithm::from("foo"), TEXT.to_owned())
105            .expect("Failed to parse");
106
107        let other = as_variant!(&parsed, Signature::Other).expect("Not parsed as Other");
108        assert_eq!(other, TEXT);
109
110        let encoded = parsed.to_base64();
111        assert_eq!(encoded, TEXT)
112    }
113}