1#[cfg(feature = "secp256k1")]
4pub use k256::ecdsa::VerifyingKey as Secp256k1;
5
6mod pub_key_request;
7mod pub_key_response;
8
9pub use pub_key_request::PubKeyRequest;
10pub use pub_key_response::PubKeyResponse;
11
12use core::convert::TryFrom;
13use core::{cmp::Ordering, fmt, str::FromStr};
14use serde::{de, ser, Deserialize, Deserializer, Serialize};
15use serde_json::Value;
16use subtle_encoding::{base64, bech32, hex};
17
18pub use crate::crypto::ed25519::VerificationKey as Ed25519;
19use crate::serializers::cow_str::CowStr;
20use crate::{error::Error, prelude::*};
21
22#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
34#[non_exhaustive]
35#[serde(tag = "type", content = "value")] pub enum PublicKey {
37 #[serde(
39 rename = "tendermint/PubKeyEd25519",
40 serialize_with = "serialize_ed25519_base64",
41 deserialize_with = "deserialize_ed25519_base64"
42 )]
43 Ed25519(Ed25519),
44
45 #[cfg(feature = "secp256k1")]
47 #[cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))]
48 #[serde(
49 rename = "tendermint/PubKeySecp256k1",
50 serialize_with = "serialize_secp256k1_base64",
51 deserialize_with = "deserialize_secp256k1_base64"
52 )]
53 Secp256k1(Secp256k1),
54}
55
56#[derive(Serialize, Deserialize)]
59struct ProtobufPublicKeyWrapper {
60 #[serde(rename = "Sum")]
61 sum: ProtobufPublicKey,
62}
63
64impl From<ProtobufPublicKeyWrapper> for PublicKey {
65 fn from(wrapper: ProtobufPublicKeyWrapper) -> Self {
66 match wrapper.sum {
67 ProtobufPublicKey::Ed25519 { ed25519 } => PublicKey::Ed25519(ed25519),
68 #[cfg(feature = "secp256k1")]
69 ProtobufPublicKey::Secp256k1 { secp256k1 } => PublicKey::Secp256k1(secp256k1),
70 }
71 }
72}
73
74#[derive(Serialize, Deserialize)]
75#[serde(tag = "type", content = "value")] enum ProtobufPublicKey {
77 #[serde(rename = "tendermint.crypto.PublicKey_Ed25519")]
78 Ed25519 {
79 #[serde(
80 serialize_with = "serialize_ed25519_base64",
81 deserialize_with = "deserialize_ed25519_base64"
82 )]
83 ed25519: Ed25519,
84 },
85
86 #[cfg(feature = "secp256k1")]
87 #[serde(rename = "tendermint.crypto.PublicKey_Secp256K1")]
88 Secp256k1 {
89 #[serde(
90 serialize_with = "serialize_secp256k1_base64",
91 deserialize_with = "deserialize_secp256k1_base64"
92 )]
93 secp256k1: Secp256k1,
94 },
95}
96
97pub fn deserialize_public_key<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
104where
105 D: Deserializer<'de>,
106{
107 let v = Value::deserialize(deserializer)?;
108 if v.as_object()
109 .map(|obj| obj.contains_key("Sum"))
110 .unwrap_or(false)
111 {
112 serde_json::from_value::<ProtobufPublicKeyWrapper>(v).map(Into::into)
113 } else {
114 serde_json::from_value::<PublicKey>(v)
115 }
116 .map_err(serde::de::Error::custom)
117}
118
119tendermint_pb_modules! {
120 use super::{PublicKey, Ed25519};
121 use pb::crypto::{PublicKey as RawPublicKey, public_key::Sum};
122 use crate::{prelude::*, Error};
123
124 impl Protobuf<RawPublicKey> for PublicKey {}
125
126 impl TryFrom<RawPublicKey> for PublicKey {
127 type Error = Error;
128
129 fn try_from(value: RawPublicKey) -> Result<Self, Self::Error> {
130 let sum = &value
131 .sum
132 .ok_or_else(|| Error::invalid_key("empty sum".to_string()))?;
133 if let Sum::Ed25519(b) = sum {
134 let key = Ed25519::try_from(&b[..])?;
135 return Ok(PublicKey::Ed25519(key));
136 }
137 #[cfg(feature = "secp256k1")]
138 if let Sum::Secp256k1(b) = sum {
139 return Self::from_raw_secp256k1(b)
140 .ok_or_else(|| Error::invalid_key("malformed key".to_string()));
141 }
142 Err(Error::invalid_key("not an ed25519 key".to_string()))
143 }
144 }
145
146 impl From<PublicKey> for RawPublicKey {
147 fn from(value: PublicKey) -> Self {
148 match value {
149 PublicKey::Ed25519(ref pk) => RawPublicKey {
150 sum: Some(Sum::Ed25519(
151 pk.as_bytes().to_vec(),
152 )),
153 },
154 #[cfg(feature = "secp256k1")]
155 PublicKey::Secp256k1(ref pk) => RawPublicKey {
156 sum: Some(Sum::Secp256k1(
157 pk.to_sec1_bytes().into(),
158 )),
159 },
160 }
161 }
162 }
163}
164
165impl PublicKey {
166 #[cfg(feature = "secp256k1")]
168 #[cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))]
169 pub fn from_raw_secp256k1(bytes: &[u8]) -> Option<PublicKey> {
170 Secp256k1::from_sec1_bytes(bytes)
171 .ok()
172 .map(PublicKey::Secp256k1)
173 }
174
175 pub fn from_raw_ed25519(bytes: &[u8]) -> Option<PublicKey> {
177 Ed25519::try_from(bytes).map(PublicKey::Ed25519).ok()
178 }
179
180 pub fn ed25519(self) -> Option<Ed25519> {
182 #[allow(unreachable_patterns)]
183 match self {
184 PublicKey::Ed25519(pk) => Some(pk),
185 _ => None,
186 }
187 }
188
189 #[cfg(feature = "secp256k1")]
191 #[cfg_attr(docsrs, doc(cfg(feature = "secp256k1")))]
192 pub fn secp256k1(self) -> Option<Secp256k1> {
193 match self {
194 PublicKey::Secp256k1(pk) => Some(pk),
195 _ => None,
196 }
197 }
198
199 pub fn to_bytes(self) -> Vec<u8> {
201 match self {
202 PublicKey::Ed25519(pk) => pk.as_bytes().to_vec(),
203 #[cfg(feature = "secp256k1")]
204 PublicKey::Secp256k1(pk) => pk.to_sec1_bytes().into(),
205 }
206 }
207
208 pub fn to_bech32(self, hrp: &str) -> String {
210 let backward_compatible_amino_prefixed_pubkey = match self {
211 PublicKey::Ed25519(ref pk) => {
212 let mut key_bytes = vec![0x16, 0x24, 0xDE, 0x64, 0x20];
213 key_bytes.extend(pk.as_bytes());
214 key_bytes
215 },
216 #[cfg(feature = "secp256k1")]
217 PublicKey::Secp256k1(ref pk) => {
218 let mut key_bytes = vec![0xEB, 0x5A, 0xE9, 0x87, 0x21];
219 key_bytes.extend(pk.to_sec1_bytes().as_ref());
220 key_bytes
221 },
222 };
223 bech32::encode(hrp, backward_compatible_amino_prefixed_pubkey)
224 }
225
226 pub fn to_hex(self) -> String {
228 String::from_utf8(hex::encode_upper(self.to_bytes())).unwrap()
229 }
230}
231
232impl From<Ed25519> for PublicKey {
233 fn from(pk: Ed25519) -> PublicKey {
234 PublicKey::Ed25519(pk)
235 }
236}
237
238#[cfg(feature = "secp256k1")]
239impl From<Secp256k1> for PublicKey {
240 fn from(pk: Secp256k1) -> PublicKey {
241 PublicKey::Secp256k1(pk)
242 }
243}
244
245impl PartialOrd for PublicKey {
246 fn partial_cmp(&self, other: &PublicKey) -> Option<Ordering> {
247 Some(self.cmp(other))
248 }
249}
250
251impl Ord for PublicKey {
252 fn cmp(&self, other: &Self) -> Ordering {
253 match self {
254 PublicKey::Ed25519(a) => match other {
255 PublicKey::Ed25519(b) => a.as_bytes().cmp(b.as_bytes()),
256 #[cfg(feature = "secp256k1")]
257 PublicKey::Secp256k1(_) => Ordering::Less,
258 },
259 #[cfg(feature = "secp256k1")]
260 PublicKey::Secp256k1(a) => match other {
261 PublicKey::Ed25519(_) => Ordering::Greater,
262 #[cfg(feature = "secp256k1")]
263 PublicKey::Secp256k1(b) => a.cmp(b),
264 },
265 }
266 }
267}
268
269#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
271pub enum TendermintKey {
272 AccountKey(PublicKey),
274
275 ConsensusKey(PublicKey),
277}
278
279impl TendermintKey {
280 pub fn new_account_key(public_key: PublicKey) -> Result<TendermintKey, Error> {
282 match public_key {
283 PublicKey::Ed25519(_) => Ok(TendermintKey::AccountKey(public_key)),
284 #[cfg(feature = "secp256k1")]
285 PublicKey::Secp256k1(_) => Ok(TendermintKey::AccountKey(public_key)),
286 }
287 }
288
289 pub fn new_consensus_key(public_key: PublicKey) -> Result<TendermintKey, Error> {
291 #[allow(unreachable_patterns)]
292 match public_key {
293 PublicKey::Ed25519(_) => Ok(TendermintKey::AccountKey(public_key)),
294 _ => Err(Error::invalid_key(
295 "only ed25519 consensus keys are supported".to_string(),
296 )),
297 }
298 }
299
300 pub fn public_key(&self) -> &PublicKey {
302 match self {
303 TendermintKey::AccountKey(key) => key,
304 TendermintKey::ConsensusKey(key) => key,
305 }
306 }
307}
308
309#[derive(Copy, Clone, Debug, Eq, PartialEq)]
311pub enum Algorithm {
312 Ed25519,
314
315 Secp256k1,
317}
318
319impl Algorithm {
320 pub fn as_str(&self) -> &str {
322 match self {
323 Algorithm::Ed25519 => "ed25519",
324 Algorithm::Secp256k1 => "secp256k1",
325 }
326 }
327}
328
329impl fmt::Display for Algorithm {
330 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
331 write!(f, "{}", self.as_str())
332 }
333}
334
335impl FromStr for Algorithm {
336 type Err = Error;
337
338 fn from_str(s: &str) -> Result<Self, Error> {
339 match s {
340 "ed25519" => Ok(Algorithm::Ed25519),
341 "secp256k1" => Ok(Algorithm::Secp256k1),
342 _ => Err(Error::parse(format!("invalid algorithm: {s}"))),
343 }
344 }
345}
346
347impl Serialize for Algorithm {
348 fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
349 self.as_str().serialize(serializer)
350 }
351}
352
353impl<'de> Deserialize<'de> for Algorithm {
354 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
355 use de::Error;
356 let s = CowStr::deserialize(deserializer)?;
357 s.parse().map_err(D::Error::custom)
358 }
359}
360
361fn serialize_ed25519_base64<S>(pk: &Ed25519, serializer: S) -> Result<S::Ok, S::Error>
363where
364 S: ser::Serializer,
365{
366 String::from_utf8(base64::encode(pk.as_bytes()))
367 .unwrap()
368 .serialize(serializer)
369}
370
371#[cfg(feature = "secp256k1")]
373fn serialize_secp256k1_base64<S>(pk: &Secp256k1, serializer: S) -> Result<S::Ok, S::Error>
374where
375 S: ser::Serializer,
376{
377 String::from_utf8(base64::encode(pk.to_sec1_bytes()))
378 .unwrap()
379 .serialize(serializer)
380}
381
382fn deserialize_ed25519_base64<'de, D>(deserializer: D) -> Result<Ed25519, D::Error>
383where
384 D: Deserializer<'de>,
385{
386 use de::Error;
387 let encoded = CowStr::deserialize(deserializer)?;
388 let bytes = base64::decode(encoded).map_err(D::Error::custom)?;
389 Ed25519::try_from(&bytes[..]).map_err(|_| D::Error::custom("invalid Ed25519 key"))
390}
391
392#[cfg(feature = "secp256k1")]
393fn deserialize_secp256k1_base64<'de, D>(deserializer: D) -> Result<Secp256k1, D::Error>
394where
395 D: Deserializer<'de>,
396{
397 use de::Error;
398 let encoded = CowStr::deserialize(deserializer)?;
399 let bytes = base64::decode(encoded).map_err(D::Error::custom)?;
400 Secp256k1::from_sec1_bytes(&bytes).map_err(|_| D::Error::custom("invalid secp256k1 key"))
401}
402
403#[cfg(test)]
404mod tests {
405 use subtle_encoding::hex;
406
407 use super::{PublicKey, TendermintKey};
408 use crate::{prelude::*, public_key::PubKeyResponse};
409
410 const EXAMPLE_CONSENSUS_KEY: &str =
411 "4A25C6640A1F72B9C975338294EF51B6D1C33158BB6ECBA69FBC3FB5A33C9DCE";
412
413 #[test]
414 fn test_consensus_serialization() {
415 let example_key = TendermintKey::ConsensusKey(
416 PublicKey::from_raw_ed25519(&hex::decode_upper(EXAMPLE_CONSENSUS_KEY).unwrap())
417 .unwrap(),
418 );
419 assert_eq!(
435 example_key.public_key().to_bech32("cosmosvalconspub"),
436 "cosmosvalconspub1zcjduepqfgjuveq2raetnjt4xwpffm63kmguxv2chdhvhf5lhslmtgeunh8qmf7exk"
437 );
438 }
439
440 #[test]
441 #[cfg(feature = "secp256k1")]
442 fn test_account_serialization() {
443 const EXAMPLE_ACCOUNT_KEY: &str =
444 "02A1633CAFCC01EBFB6D78E39F687A1F0995C62FC95F51EAD10A02EE0BE551B5DC";
445 let example_key = TendermintKey::AccountKey(
446 PublicKey::from_raw_secp256k1(&hex::decode_upper(EXAMPLE_ACCOUNT_KEY).unwrap())
447 .unwrap(),
448 );
449 assert_eq!(
450 example_key.public_key().to_bech32("cosmospub"),
451 "cosmospub1addwnpepq2skx090esq7h7md0r3e76r6ruyet330e904r6k3pgpwuzl92x6actrt4uq"
452 );
453 }
454
455 #[test]
456 fn json_parsing() {
457 let json_string = "{\"type\":\"tendermint/PubKeyEd25519\",\"value\":\"RblzMO4is5L1hZz6wo4kPbptzOyue6LTk4+lPhD1FRk=\"}";
458 let pubkey: PublicKey = serde_json::from_str(json_string).unwrap();
459
460 assert_eq!(
461 pubkey.ed25519().unwrap().as_bytes(),
462 [
463 69, 185, 115, 48, 238, 34, 179, 146, 245, 133, 156, 250, 194, 142, 36, 61, 186,
464 109, 204, 236, 174, 123, 162, 211, 147, 143, 165, 62, 16, 245, 21, 25
465 ]
466 );
467
468 let reserialized_json = serde_json::to_string(&pubkey).unwrap();
469 assert_eq!(reserialized_json.as_str(), json_string);
470 }
471
472 tendermint_pb_modules! {
473 use super::*;
474 use pb::privval::PubKeyResponse as RawPubKeyResponse;
475
476 #[test]
477 fn test_ed25519_pubkey_msg() {
478 let encoded = vec![
501 0xa, 0x22, 0xa, 0x20, 0xd7, 0x5a, 0x98, 0x1, 0x82, 0xb1, 0xa, 0xb7, 0xd5, 0x4b, 0xfe,
502 0xd3, 0xc9, 0x64, 0x7, 0x3a, 0xe, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x2,
503 0x1a, 0x68, 0xf7, 0x7, 0x51, 0x1a,
504 ];
505
506 let msg = PubKeyResponse {
507 pub_key: Some(
508 PublicKey::from_raw_ed25519(&[
509 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14,
510 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26,
511 ])
512 .unwrap(),
513 ),
514 error: None,
515 };
516 let got = Protobuf::<RawPubKeyResponse>::encode_vec(&msg).unwrap();
517
518 assert_eq!(got, encoded);
519 let decoded = <PubKeyResponse as Protobuf<RawPubKeyResponse>>::decode_vec(
520 &encoded
521 ).unwrap();
522 assert_eq!(decoded, msg);
523 }
524 }
525}