Skip to content
This repository has been archived by the owner on Jun 3, 2020. It is now read-only.

Commit

Permalink
tendermint-rs: Impl Serialize and Deserialize for PublicKey
Browse files Browse the repository at this point in the history
Adds serde serializers/deserializers for PublicKey types which support
the JSON serialization used by the JSONRPC interface.
  • Loading branch information
tony-iqlusion committed Apr 15, 2019
1 parent 58e41e9 commit 4e2af2c
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions tendermint-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ tai64 = { version = "1", optional = true, features = ["chrono"] }
x25519-dalek = { version = "0.5", optional = true, default-features = false, features = ["u64_backend"] }
zeroize = { version = "0.6", optional = true }

[dev-dependencies]
serde_json = "1"

[features]
default = ["serde", "tai64"]
amino-types = ["prost-amino", "prost-amino-derive"]
Expand Down
96 changes: 96 additions & 0 deletions tendermint-rs/src/public_keys.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
//! Public keys used in Tendermint networks

use crate::error::Error;
#[cfg(feature = "serde")]
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
use signatory::{ecdsa::curve::secp256k1, ed25519};
use std::ops::Deref;
#[cfg(feature = "serde")]
use subtle_encoding::base64;
use subtle_encoding::{bech32, hex};

/// Public keys allowed in Tendermint protocols
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", content = "value"))]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub enum PublicKey {
/// Ed25519 keys
#[cfg_attr(
feature = "serde",
serde(
rename = "tendermint/PubKeyEd25519",
serialize_with = "serialize_ed25519_base64",
deserialize_with = "deserialize_ed25519_base64"
)
)]
Ed25519(ed25519::PublicKey),

/// Secp256k1 keys
#[cfg_attr(
feature = "serde",
serde(
rename = "tendermint/PubKeySecp256k1",
serialize_with = "serialize_secp256k1_base64",
deserialize_with = "deserialize_secp256k1_base64"
)
)]
Secp256k1(secp256k1::PublicKey),
}

Expand Down Expand Up @@ -64,6 +86,62 @@ impl PublicKey {
}
}

/// Serialize the bytes of an Ed25519 public key as Base64. Used for serializing JSON
#[cfg(feature = "serde")]
fn serialize_ed25519_base64<S>(
pk: &signatory::ed25519::PublicKey,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
String::from_utf8(base64::encode(pk.as_bytes()))
.unwrap()
.serialize(serializer)
}

/// Serialize the bytes of a secp256k1 ECDSA public key as Base64. Used for serializing JSON
#[cfg(feature = "serde")]
fn serialize_secp256k1_base64<S>(
pk: &signatory::ecdsa::curve::secp256k1::PublicKey,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
String::from_utf8(base64::encode(pk.as_bytes()))
.unwrap()
.serialize(serializer)
}

#[cfg(feature = "serde")]
fn deserialize_ed25519_base64<'de, D>(
deserializer: D,
) -> Result<signatory::ed25519::PublicKey, D::Error>
where
D: Deserializer<'de>,
{
let bytes = base64::decode(String::deserialize(deserializer)?.as_bytes())
.map_err(|e| D::Error::custom(format!("{}", e)))?;

signatory::ed25519::PublicKey::from_bytes(&bytes)
.map_err(|e| D::Error::custom(format!("{}", e)))
}

#[cfg(feature = "serde")]
fn deserialize_secp256k1_base64<'de, D>(
deserializer: D,
) -> Result<signatory::ecdsa::curve::secp256k1::PublicKey, D::Error>
where
D: Deserializer<'de>,
{
let bytes = base64::decode(String::deserialize(deserializer)?.as_bytes())
.map_err(|e| D::Error::custom(format!("{}", e)))?;

signatory::ecdsa::curve::secp256k1::PublicKey::from_bytes(&bytes)
.map_err(|e| D::Error::custom(format!("{}", e)))
}

impl From<ed25519::PublicKey> for PublicKey {
fn from(pk: ed25519::PublicKey) -> PublicKey {
PublicKey::Ed25519(pk)
Expand Down Expand Up @@ -133,4 +211,22 @@ mod tests {
"cosmospub1addwnpepq2skx090esq7h7md0r3e76r6ruyet330e904r6k3pgpwuzl92x6actrt4uq"
);
}

#[cfg(feature = "serde")]
#[test]
fn json_parsing() {
let json_string = "{\"type\":\"tendermint/PubKeyEd25519\",\"value\":\"RblzMO4is5L1hZz6wo4kPbptzOyue6LTk4+lPhD1FRk=\"}";
let pubkey: PublicKey = serde_json::from_str(json_string).unwrap();

assert_eq!(
pubkey.ed25519().unwrap().as_ref(),
[
69, 185, 115, 48, 238, 34, 179, 146, 245, 133, 156, 250, 194, 142, 36, 61, 186,
109, 204, 236, 174, 123, 162, 211, 147, 143, 165, 62, 16, 245, 21, 25
]
);

let reserialized_json = serde_json::to_string(&pubkey).unwrap();
assert_eq!(reserialized_json.as_str(), json_string);
}
}

0 comments on commit 4e2af2c

Please sign in to comment.