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

Support for secp256k1 keys in tendermint-rs #181

Merged
merged 2 commits into from
Feb 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 35 additions & 15 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ serde_derive = "1"
serde_json = "1"
sha2 = "0.8"
signal-hook = "0.1.7"
signatory = { version = "0.11", features = ["ed25519"] }
signatory = { version = "0.11.1", features = ["ed25519", "ecdsa"] }
signatory-dalek = "0.11"
signatory-secp256k1 = "0.11"
signatory-ledger-tm = { version = "0.11", optional = true }
subtle-encoding = "0.3"
tendermint = { version = "0.2", path = "tendermint-rs" }
Expand Down
2 changes: 1 addition & 1 deletion tendermint-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ rand_os = { version = "0.1", optional = true }
ring = { version = "0.14", optional = true }
serde = { version = "1", optional = true }
serde_derive = { version = "1", optional = true }
signatory = { version = "0.11", optional = true, features = ["ed25519"] }
signatory = { version = "0.11.1", optional = true, features = ["ed25519","ecdsa"] }
signatory-dalek = { version = "0.11", optional = true }
sha2 = { version = "0.8", optional = true, default-features = false }
subtle-encoding = { version = "0.3", features = ["bech32-preview"] }
Expand Down
120 changes: 103 additions & 17 deletions tendermint-rs/src/public_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,119 @@

use crate::error::Error;
use sha2::{Digest, Sha256};
use signatory::ed25519;
use signatory::{ecdsa::curve::secp256k1, ed25519};
use std::fmt::{self, Display};
use subtle_encoding::bech32;

/// Validator signing keys used for authenticating consensus protocol messages
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum ConsensusKey {
pub enum TendermintKey {
/// Ed25519 consensus keys
Ed25519(ed25519::PublicKey),
/// Secp256k1 consensus keys
Secp256k1(secp256k1::PublicKey),
}

impl ConsensusKey {
/// Validator signing keys used for authenticating consensus protocol messages
pub struct ConsensusKey(TendermintKey);
/// User signing keys used for interacting with accounts in the state machine
pub struct AccountKey(TendermintKey);

impl TendermintKey {
/// From raw secp256k1 public key bytes
pub fn from_raw_secp256k1(bytes: &[u8]) -> Result<TendermintKey, Error> {
Ok(TendermintKey::Secp256k1(secp256k1::PublicKey::from_bytes(
bytes,
)?))
}

/// From raw Ed25519 public key bytes
pub fn from_raw_ed25519(bytes: &[u8]) -> Result<ConsensusKey, Error> {
Ok(ConsensusKey::Ed25519(ed25519::PublicKey::from_bytes(
pub fn from_raw_ed25519(bytes: &[u8]) -> Result<TendermintKey, Error> {
Ok(TendermintKey::Ed25519(ed25519::PublicKey::from_bytes(
bytes,
)?))
}

/// Get Ed25519 public key
pub fn ed25519(self) -> Option<ed25519::PublicKey> {
match self {
ConsensusKey::Ed25519(pk) => Some(pk),
TendermintKey::Ed25519(pk) => Some(pk),
_ => None,
}
}
}

impl Display for ConsensusKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//Amino prefix for Pubkey
let mut key_bytes: Vec<u8> = vec![0x16, 0x24, 0xDE, 0x64, 0x20];
match self {
ConsensusKey::Ed25519(ref pk) => {
let key_bytes: Vec<u8> = match self.0 {
TendermintKey::Ed25519(ref pk) => {
//Amino prefix for Pubkey
let mut key_bytes = vec![0x16, 0x24, 0xDE, 0x64, 0x20];
key_bytes.extend(pk.as_bytes());
bech32::encode("cosmosvalconspub", &key_bytes).fmt(f)
key_bytes
}
}
TendermintKey::Secp256k1(ref pk) => {
let mut key_bytes = vec![0xEB, 0x5A, 0xE9, 0x87, 0x21];
key_bytes.extend(pk.as_bytes());
key_bytes
}
};
bech32::encode("cosmosvalconspub", &key_bytes).fmt(f)
}
}

impl Display for AccountKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let key_bytes: Vec<u8> = match self.0 {
TendermintKey::Ed25519(ref pk) => {
//Amino prefix for Pubkey
let mut key_bytes = vec![0x16, 0x24, 0xDE, 0x64, 0x20];
key_bytes.extend(pk.as_bytes());
key_bytes
}
TendermintKey::Secp256k1(ref pk) => {
let mut key_bytes = vec![0xEB, 0x5A, 0xE9, 0x87, 0x21];
key_bytes.extend(pk.as_bytes());
key_bytes
}
};
bech32::encode("cosmospub", &key_bytes).fmt(f)
}
}

impl From<ed25519::PublicKey> for TendermintKey {
fn from(pk: ed25519::PublicKey) -> TendermintKey {
TendermintKey::Ed25519(pk)
}
}

impl From<secp256k1::PublicKey> for TendermintKey {
fn from(pk: secp256k1::PublicKey) -> TendermintKey {
TendermintKey::Secp256k1(pk)
}
}

impl From<ed25519::PublicKey> for ConsensusKey {
fn from(pk: ed25519::PublicKey) -> ConsensusKey {
ConsensusKey::Ed25519(pk)
ConsensusKey(TendermintKey::Ed25519(pk))
}
}

impl From<secp256k1::PublicKey> for ConsensusKey {
fn from(pk: secp256k1::PublicKey) -> ConsensusKey {
ConsensusKey(TendermintKey::Secp256k1(pk))
}
}

impl From<ed25519::PublicKey> for AccountKey {
fn from(pk: ed25519::PublicKey) -> AccountKey {
AccountKey(TendermintKey::Ed25519(pk))
}
}

impl From<secp256k1::PublicKey> for AccountKey {
fn from(pk: secp256k1::PublicKey) -> AccountKey {
AccountKey(TendermintKey::Secp256k1(pk))
}
}

Expand Down Expand Up @@ -93,7 +163,7 @@ impl From<ed25519::PublicKey> for SecretConnectionKey {

#[cfg(test)]
mod tests {
use super::{ConsensusKey, SecretConnectionKey};
use super::{AccountKey, ConsensusKey, SecretConnectionKey, TendermintKey};
use subtle_encoding::hex;

const EXAMPLE_SECRET_CONN_KEY: &str =
Expand All @@ -117,13 +187,29 @@ mod tests {

#[test]
fn test_consensus_serialization() {
let example_key =
ConsensusKey::from_raw_ed25519(&hex::decode_upper(EXAMPLE_CONSENSUS_KEY).unwrap())
.unwrap();
let example_key = ConsensusKey(
TendermintKey::from_raw_ed25519(&hex::decode_upper(EXAMPLE_CONSENSUS_KEY).unwrap())
.unwrap(),
);

assert_eq!(
example_key.to_string(),
"cosmosvalconspub1zcjduepqfgjuveq2raetnjt4xwpffm63kmguxv2chdhvhf5lhslmtgeunh8qmf7exk"
);
}

const EXAMPLE_ACCOUNT_KEY: &str =
"02A1633CAFCC01EBFB6D78E39F687A1F0995C62FC95F51EAD10A02EE0BE551B5DC";
#[test]
fn test_account_serialization() {
let example_key = AccountKey(
TendermintKey::from_raw_secp256k1(&hex::decode_upper(EXAMPLE_ACCOUNT_KEY).unwrap())
.unwrap(),
);

assert_eq!(
example_key.to_string(),
"cosmospub1addwnpepq2skx090esq7h7md0r3e76r6ruyet330e904r6k3pgpwuzl92x6actrt4uq"
);
}
}