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