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};
#[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 {
#[cfg_attr(
feature = "serde",
serde(
rename = "tendermint/PubKeyEd25519",
serialize_with = "serialize_ed25519_base64",
deserialize_with = "deserialize_ed25519_base64"
)
)]
Ed25519(ed25519::PublicKey),
#[cfg_attr(
feature = "serde",
serde(
rename = "tendermint/PubKeySecp256k1",
serialize_with = "serialize_secp256k1_base64",
deserialize_with = "deserialize_secp256k1_base64"
)
)]
Secp256k1(secp256k1::PublicKey),
}
impl PublicKey {
pub fn from_raw_secp256k1(bytes: &[u8]) -> Result<PublicKey, Error> {
Ok(PublicKey::Secp256k1(secp256k1::PublicKey::from_bytes(
bytes,
)?))
}
pub fn from_raw_ed25519(bytes: &[u8]) -> Result<PublicKey, Error> {
Ok(PublicKey::Ed25519(ed25519::PublicKey::from_bytes(bytes)?))
}
pub fn ed25519(self) -> Option<ed25519::PublicKey> {
match self {
PublicKey::Ed25519(pk) => Some(pk),
_ => None,
}
}
pub fn to_amino_bytes(self) -> Vec<u8> {
match self {
PublicKey::Ed25519(ref pk) => {
let mut key_bytes = vec![0x16, 0x24, 0xDE, 0x64, 0x20];
key_bytes.extend(pk.as_bytes());
key_bytes
}
PublicKey::Secp256k1(ref pk) => {
let mut key_bytes = vec![0xEB, 0x5A, 0xE9, 0x87, 0x21];
key_bytes.extend(pk.as_bytes());
key_bytes
}
}
}
pub fn to_bech32(self, hrp: &str) -> String {
bech32::encode(hrp, self.to_amino_bytes())
}
pub fn to_hex(self) -> String {
String::from_utf8(hex::encode_upper(self.to_amino_bytes())).unwrap()
}
}
#[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)
}
#[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)
}
}
impl From<secp256k1::PublicKey> for PublicKey {
fn from(pk: secp256k1::PublicKey) -> PublicKey {
PublicKey::Secp256k1(pk)
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub enum TendermintKey {
AccountKey(PublicKey),
ConsensusKey(PublicKey),
}
impl Deref for TendermintKey {
type Target = PublicKey;
fn deref(&self) -> &PublicKey {
match self {
TendermintKey::AccountKey(key) => key,
TendermintKey::ConsensusKey(key) => key,
}
}
}
#[cfg(test)]
mod tests {
use super::{PublicKey, TendermintKey};
use subtle_encoding::hex;
const EXAMPLE_CONSENSUS_KEY: &str =
"4A25C6640A1F72B9C975338294EF51B6D1C33158BB6ECBA69FBC3FB5A33C9DCE";
#[test]
fn test_consensus_serialization() {
let example_key = TendermintKey::ConsensusKey(
PublicKey::from_raw_ed25519(&hex::decode_upper(EXAMPLE_CONSENSUS_KEY).unwrap())
.unwrap(),
);
assert_eq!(
example_key.to_bech32("cosmosvalconspub"),
"cosmosvalconspub1zcjduepqfgjuveq2raetnjt4xwpffm63kmguxv2chdhvhf5lhslmtgeunh8qmf7exk"
);
}
const EXAMPLE_ACCOUNT_KEY: &str =
"02A1633CAFCC01EBFB6D78E39F687A1F0995C62FC95F51EAD10A02EE0BE551B5DC";
#[test]
fn test_account_serialization() {
let example_key = TendermintKey::AccountKey(
PublicKey::from_raw_secp256k1(&hex::decode_upper(EXAMPLE_ACCOUNT_KEY).unwrap())
.unwrap(),
);
assert_eq!(
example_key.to_bech32("cosmospub"),
"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);
}
}