iop_keyvault/multicipher/
pk.rs1use super::*;
2
3#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
7pub enum MPublicKey {
8 Ed25519(EdPublicKey),
12 Secp256k1(SecpPublicKey),
16}
17
18impl MPublicKey {
19 pub const PREFIX: char = 'p';
21
22 pub fn suite(&self) -> CipherSuite {
24 match self {
25 Self::Ed25519(_) => CipherSuite::Ed25519,
26 Self::Secp256k1(_) => CipherSuite::Secp256k1,
27 }
28 }
29
30 pub fn to_bytes(&self) -> Vec<u8> {
33 String::from(self).as_bytes().to_vec()
34 }
35
36 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}