iop_keyvault/multicipher/
pk.rs

1use super::*;
2
3/// Multicipher [`PublicKey`]
4///
5/// [`PublicKey`]: ../trait.AsymmetricCrypto.html#associatedtype.PublicKey
6#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
7pub enum MPublicKey {
8    /// The public key tagged with this variant belongs to the [`ed25519`] module
9    ///
10    /// [`ed25519`]: ../ed25519/index.html
11    Ed25519(EdPublicKey),
12    /// The public key tagged with this variant belongs to the [`secp256k1`] module
13    ///
14    /// [`secp256k1`]: ../secp256k1/index.html
15    Secp256k1(SecpPublicKey),
16}
17
18impl MPublicKey {
19    /// All multicipher public keys start with this prefix
20    pub const PREFIX: char = 'p';
21
22    /// The ciphersuite that this public key belongs to
23    pub fn suite(&self) -> CipherSuite {
24        match self {
25            Self::Ed25519(_) => CipherSuite::Ed25519,
26            Self::Secp256k1(_) => CipherSuite::Secp256k1,
27        }
28    }
29
30    /// Even the binary representation of a multicipher public key is readable with this.
31    // TODO Should we really keep it like this?
32    pub fn to_bytes(&self) -> Vec<u8> {
33        String::from(self).as_bytes().to_vec()
34    }
35
36    /// Even the binary representation of a multicipher public key is readable with this.
37    // TODO Should we really keep it like this?
38    pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Self> {
39        let string = String::from_utf8(bytes.as_ref().to_owned())?;
40        string.parse()
41    }
42
43    fn to_inner_bytes(&self) -> Vec<u8> {
44        match self {
45            Self::Ed25519(edpk) => edpk.to_bytes(),
46            Self::Secp256k1(secppk) => secppk.to_bytes(),
47        }
48    }
49
50    fn from_inner_bytes<B: AsRef<[u8]>>(suite: char, inner_bytes: B) -> Result<Self> {
51        match CipherSuite::from_char(suite)? {
52            CipherSuite::Ed25519 => Ok(Self::Ed25519(EdPublicKey::from_bytes(inner_bytes)?)),
53            CipherSuite::Secp256k1 => Ok(Self::Secp256k1(SecpPublicKey::from_bytes(inner_bytes)?)),
54        }
55    }
56}
57
58impl PublicKey<MultiCipher> for MPublicKey {
59    fn key_id(&self) -> MKeyId {
60        match self {
61            Self::Ed25519(edpk) => MKeyId::from(edpk.key_id()),
62            Self::Secp256k1(secppk) => MKeyId::from(secppk.key_id()),
63        }
64    }
65
66    fn validate_id(&self, key_id: &MKeyId) -> bool {
67        match self {
68            Self::Ed25519(edpk) => {
69                if let MKeyId::Ed25519(edid) = key_id {
70                    return edpk.validate_id(edid);
71                }
72            }
73            Self::Secp256k1(secppk) => {
74                if let MKeyId::Secp256k1(secpid) = key_id {
75                    return secppk.validate_id(secpid);
76                }
77            }
78        };
79
80        false
81    }
82
83    fn verify<D: AsRef<[u8]>>(&self, data: D, sig: &MSignature) -> bool {
84        match self {
85            Self::Ed25519(edpk) => {
86                if let MSignature::Ed25519(edsig) = sig {
87                    return edpk.verify(data, edsig);
88                }
89            }
90            Self::Secp256k1(secppk) => {
91                if let MSignature::Secp256k1(secpsig) = sig {
92                    return secppk.verify(data, secpsig);
93                }
94            }
95        };
96
97        false
98    }
99}
100
101impl Serialize for MPublicKey {
102    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
103    where
104        S: Serializer,
105    {
106        let erased = ErasedBytes { suite: self.suite().as_byte(), value: self.to_inner_bytes() };
107        erased.serialize(serializer)
108    }
109}
110
111fn deser(erased: ErasedBytes) -> Result<MPublicKey> {
112    MPublicKey::from_inner_bytes(erased.suite as char, &erased.value)
113}
114
115impl<'de> Deserialize<'de> for MPublicKey {
116    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
117    where
118        D: Deserializer<'de>,
119    {
120        ErasedBytes::deserialize(deserializer)
121            .and_then(|b| deser(b).map_err(|e| serde::de::Error::custom(e.to_string())))
122    }
123}
124
125impl From<&MPublicKey> for String {
126    fn from(src: &MPublicKey) -> Self {
127        let mut output = multibase::encode(multibase::Base::Base58Btc, src.to_inner_bytes());
128        output.insert(0, src.suite().as_char());
129        output.insert(0, MPublicKey::PREFIX);
130        output
131    }
132}
133
134impl From<MPublicKey> for String {
135    fn from(src: MPublicKey) -> Self {
136        (&src).into()
137    }
138}
139
140impl std::fmt::Display for MPublicKey {
141    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
142        write!(f, "{}", String::from(self))
143    }
144}
145
146impl std::fmt::Debug for MPublicKey {
147    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
148        (self as &dyn std::fmt::Display).fmt(f)
149    }
150}
151
152impl std::str::FromStr for MPublicKey {
153    type Err = anyhow::Error;
154    fn from_str(src: &str) -> Result<Self> {
155        let mut chars = src.chars();
156        ensure!(
157            chars.next() == Some(Self::PREFIX),
158            "Public keys must start with '{}'",
159            Self::PREFIX
160        );
161        if let Some(suite) = chars.next() {
162            let (_base, binary) = multibase::decode(chars.as_str())?;
163            Self::from_inner_bytes(suite, &binary)
164        } else {
165            Err(anyhow!("No crypto suite found"))
166        }
167    }
168}
169
170impl From<EdPublicKey> for MPublicKey {
171    fn from(src: EdPublicKey) -> Self {
172        Self::Ed25519(src)
173    }
174}
175
176impl From<SecpPublicKey> for MPublicKey {
177    fn from(src: SecpPublicKey) -> Self {
178        Self::Secp256k1(src)
179    }
180}
181
182#[cfg(test)]
183mod test {
184    mod parse_public_key {
185        use crate::ed25519::EdPublicKey;
186        use crate::multicipher::{CipherSuite, MPublicKey};
187
188        #[allow(dead_code)]
189        fn case(input: &str, pk_hex: &str) {
190            let pk_bytes = hex::decode(pk_hex).unwrap();
191            let pk1 = EdPublicKey::from_bytes(&pk_bytes).unwrap();
192            let erased_pk1 = MPublicKey::from(pk1);
193            assert_eq!(erased_pk1.to_string(), input);
194
195            let erased_pk2 = input.parse::<MPublicKey>().unwrap();
196            assert_eq!(erased_pk2, erased_pk1);
197        }
198
199        #[test]
200        fn test_1() {
201            case(
202                "pez11111111111111111111111111111111",
203                "0000000000000000000000000000000000000000000000000000000000000000",
204            );
205        }
206
207        #[test]
208        fn test_2() {
209            case(
210                "pezAgmjPHe5Qs4VakvXHGnd6NsYjaxt4suMUtf39TayrSfb",
211                "8fe9693f8fa62a4305a140b9764c5ee01e455963744fe18204b4fb948249308a",
212            );
213        }
214
215        #[test]
216        fn test_3() {
217            case(
218                "pezFVen3X669xLzsi6N2V91DoiyzHzg1uAgqiT8jZ9nS96Z",
219                "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
220            );
221        }
222
223        #[test]
224        fn test_4() {
225            case(
226                "pez586Z7H2vpX9qNhN2T4e9Utugie3ogjbxzGaMtM3E6HR5",
227                "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c",
228            );
229        }
230
231        #[test]
232        fn test_5() {
233            case(
234                "pezHyx62wPQGyvXCoihZq1BrbUjBRh2LuNxWiiqMkfAuSZr",
235                "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",
236            );
237        }
238
239        #[test]
240        fn ed_suite() {
241            let pk = "pez11111111111111111111111111111111".parse::<MPublicKey>().unwrap();
242            assert_eq!(pk.suite(), CipherSuite::Ed25519);
243            assert!(matches!(&pk, MPublicKey::Ed25519(_)));
244            assert!(!matches!(&pk, MPublicKey::Secp256k1(_)));
245        }
246
247        #[test]
248        fn secp_suite() {
249            let pk =
250                "psz291QGsvwafGPkKMu6MUsXThWRcBRzRf6pcVPM1Pst6WgW".parse::<MPublicKey>().unwrap();
251            assert_eq!(pk.suite(), CipherSuite::Secp256k1);
252            assert!(!matches!(&pk, MPublicKey::Ed25519(_)));
253            assert!(matches!(&pk, MPublicKey::Secp256k1(_)));
254        }
255
256        #[test]
257        #[should_panic(expected = "Unknown crypto suite 'g'")]
258        fn invalid_suite() {
259            let _pk =
260                "pgzAgmjPHe5Qs4VakvXHGnd6NsYjaxt4suMUtf39TayrSfb".parse::<MPublicKey>().unwrap();
261        }
262
263        #[test]
264        #[should_panic(expected = "No crypto suite found")]
265        fn missing_suite() {
266            let _pk = "p".parse::<MPublicKey>().unwrap();
267        }
268
269        #[test]
270        #[should_panic(expected = "Public keys must start with 'p'")]
271        fn invalid_type() {
272            let _pk = "Fez21JXEtMzXjbCK6BAYFU9ewX".parse::<MPublicKey>().unwrap();
273        }
274
275        #[test]
276        #[should_panic(expected = "Public keys must start with 'p'")]
277        fn empty() {
278            let _pk = "".parse::<MPublicKey>().unwrap();
279        }
280    }
281
282    mod serde_key_id {
283        use crate::multicipher::MPublicKey;
284
285        #[test]
286        fn messagepack_serialization() {
287            let pk_str = "pezAgmjPHe5Qs4VakvXHGnd6NsYjaxt4suMUtf39TayrSfb";
288            let pk = pk_str.parse::<MPublicKey>().unwrap();
289            let pk_bin = rmp_serde::to_vec(&pk).unwrap();
290
291            assert_eq!(
292                pk_bin,
293                vec![
294                    146, 101, 196, 32, 143, 233, 105, 63, 143, 166, 42, 67, 5, 161, 64, 185, 118,
295                    76, 94, 224, 30, 69, 89, 99, 116, 79, 225, 130, 4, 180, 251, 148, 130, 73, 48,
296                    138
297                ]
298            );
299
300            let pk_deser: MPublicKey = rmp_serde::from_slice(&pk_bin).unwrap();
301            let pk_tostr = pk_deser.to_string();
302            assert_eq!(pk, pk_deser);
303            assert_eq!(pk_str, pk_tostr);
304        }
305
306        #[test]
307        fn json_serialization() {
308            let pk_str = "pezAgmjPHe5Qs4VakvXHGnd6NsYjaxt4suMUtf39TayrSfb";
309            let pk = pk_str.parse::<MPublicKey>().unwrap();
310            let pk_bin = serde_json::to_vec(&pk).unwrap();
311
312            assert_eq!(pk_bin, br#"{"s":101,"v":[143,233,105,63,143,166,42,67,5,161,64,185,118,76,94,224,30,69,89,99,116,79,225,130,4,180,251,148,130,73,48,138]}"#.to_vec());
313
314            let pk_deser: MPublicKey = serde_json::from_slice(&pk_bin).unwrap();
315            let pk_tostr = pk_deser.to_string();
316            assert_eq!(pk, pk_deser);
317            assert_eq!(pk_str, pk_tostr);
318        }
319    }
320}