From 0cf605d035a325803a7b65eee77de4100cb7ab9b Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 8 Dec 2021 00:44:50 -0800 Subject: [PATCH] Use ed25519-consensus instead of ed25519-dalek Closes #355 (see that issue for more context; `ed25519-consensus` is a fork of `ed25519-zebra` that's Zcash-independent). This change ensures that `tendermint-rs` has the same signature verification as `tendermint`, which uses the validation criteria provided by the Go `ed25519consensus` library. --- config/src/node_key.rs | 2 +- p2p/Cargo.toml | 4 +-- p2p/src/error.rs | 2 -- p2p/src/secret_connection.rs | 40 +++++++++------------ p2p/src/secret_connection/amino_types.rs | 10 +++--- p2p/src/secret_connection/protocol.rs | 15 ++++---- p2p/src/secret_connection/public_key.rs | 24 +++++++------ pbt-gen/src/time.rs | 4 --- proto/src/serializers/timestamp.rs | 1 - tendermint/Cargo.toml | 2 +- tendermint/src/account.rs | 2 +- tendermint/src/error.rs | 3 +- tendermint/src/private_key.rs | 33 +++++++++++++---- tendermint/src/public_key.rs | 21 ++++++----- tendermint/src/signature.rs | 10 ++++-- tendermint/src/time.rs | 1 - tendermint/src/validator.rs | 2 +- test/Cargo.toml | 4 +-- test/src/test/unit/p2p/secret_connection.rs | 8 ++--- testgen/Cargo.toml | 2 +- testgen/src/helpers.rs | 10 ++---- testgen/src/validator.rs | 18 +++++----- testgen/src/vote.rs | 6 ++-- 23 files changed, 117 insertions(+), 107 deletions(-) diff --git a/config/src/node_key.rs b/config/src/node_key.rs index 190265f6d..a5b497199 100644 --- a/config/src/node_key.rs +++ b/config/src/node_key.rs @@ -36,7 +36,7 @@ impl NodeKey { pub fn public_key(&self) -> PublicKey { #[allow(unreachable_patterns)] match &self.priv_key { - PrivateKey::Ed25519(keypair) => keypair.public.into(), + PrivateKey::Ed25519(signing_key) => PublicKey::Ed25519(signing_key.verification_key()), _ => unreachable!(), } } diff --git a/p2p/Cargo.toml b/p2p/Cargo.toml index 8f91fda9f..6e97b69f3 100644 --- a/p2p/Cargo.toml +++ b/p2p/Cargo.toml @@ -28,7 +28,7 @@ amino = ["prost-derive"] [dependencies] chacha20poly1305 = { version = "0.8", default-features = false, features = ["reduced-round"] } -ed25519-dalek = { version = "1", default-features = false } +ed25519-consensus = { version = "1.2", default-features = false } eyre = { version = "0.6", default-features = false } flume = { version = "0.10.7", default-features = false } hkdf = { version = "0.10.0", default-features = false } @@ -37,7 +37,7 @@ prost = { version = "0.9", default-features = false } rand_core = { version = "0.5", default-features = false, features = ["std"] } sha2 = { version = "0.9", default-features = false } subtle = { version = "2", default-features = false } -x25519-dalek = { version = "1.1", default-features = false } +x25519-dalek = { version = "1.1", default-features = false, features = ["u64_backend"] } zeroize = { version = "1", default-features = false } signature = { version = "1.3.0", default-features = false } aead = { version = "0.4.1", default-features = false } diff --git a/p2p/src/error.rs b/p2p/src/error.rs index a0530c68d..730c2d8cf 100644 --- a/p2p/src/error.rs +++ b/p2p/src/error.rs @@ -2,7 +2,6 @@ use flex_error::{define_error, DisplayOnly}; use prost::DecodeError; -use signature::Error as SignatureError; define_error! { Error { @@ -36,7 +35,6 @@ define_error! { | _ | { "public key missing" }, Signature - [ DisplayOnly ] | _ | { "signature error" }, UnsupportedKey diff --git a/p2p/src/secret_connection.rs b/p2p/src/secret_connection.rs index 28c165891..301303c54 100644 --- a/p2p/src/secret_connection.rs +++ b/p2p/src/secret_connection.rs @@ -13,7 +13,6 @@ use chacha20poly1305::{ aead::{generic_array::GenericArray, AeadInPlace, NewAead}, ChaCha20Poly1305, }; -use ed25519_dalek::{self as ed25519, Signer, Verifier}; use merlin::Transcript; use rand_core::OsRng; use subtle::ConstantTimeEq; @@ -58,7 +57,7 @@ pub struct Handshake { /// `AwaitingEphKey` means we're waiting for the remote ephemeral pubkey. pub struct AwaitingEphKey { - local_privkey: ed25519::Keypair, + local_privkey: ed25519_consensus::SigningKey, local_eph_privkey: Option, } @@ -68,7 +67,7 @@ pub struct AwaitingAuthSig { kdf: Kdf, recv_cipher: ChaCha20Poly1305, send_cipher: ChaCha20Poly1305, - local_signature: ed25519::Signature, + local_signature: ed25519_consensus::Signature, } #[allow(clippy::use_self)] @@ -76,7 +75,7 @@ impl Handshake { /// Initiate a handshake. #[must_use] pub fn new( - local_privkey: ed25519::Keypair, + local_privkey: ed25519_consensus::SigningKey, protocol_version: Version, ) -> (Self, EphemeralPublic) { // Generate an ephemeral key for perfect forward secrecy. @@ -148,9 +147,9 @@ impl Handshake { // Sign the challenge bytes for authentication. let local_signature = if self.protocol_version.has_transcript() { - sign_challenge(&sc_mac, &self.state.local_privkey)? + self.state.local_privkey.sign(&sc_mac) } else { - sign_challenge(&kdf.challenge, &self.state.local_privkey)? + self.state.local_privkey.sign(&kdf.challenge) }; Ok(Handshake { @@ -183,22 +182,23 @@ impl Handshake { let remote_pubkey = match pk_sum { proto::crypto::public_key::Sum::Ed25519(ref bytes) => { - ed25519::PublicKey::from_bytes(bytes).map_err(Error::signature) + ed25519_consensus::VerificationKey::try_from(&bytes[..]) + .map_err(|_| Error::signature()) } _ => Err(Error::unsupported_key()), }?; - let remote_sig = - ed25519::Signature::try_from(auth_sig_msg.sig.as_slice()).map_err(Error::signature)?; + let remote_sig = ed25519_consensus::Signature::try_from(auth_sig_msg.sig.as_slice()) + .map_err(|_| Error::signature())?; if self.protocol_version.has_transcript() { remote_pubkey - .verify(&self.state.sc_mac, &remote_sig) - .map_err(Error::signature)?; + .verify(&remote_sig, &self.state.sc_mac) + .map_err(|_| Error::signature())?; } else { remote_pubkey - .verify(&self.state.kdf.challenge, &remote_sig) - .map_err(Error::signature)?; + .verify(&remote_sig, &self.state.kdf.challenge) + .map_err(|_| Error::signature())?; } // We've authorized. @@ -276,7 +276,7 @@ impl SecretConnection { /// * if receiving the signature fails pub fn new( mut io_handler: IoHandler, - local_privkey: ed25519::Keypair, + local_privkey: ed25519_consensus::SigningKey, protocol_version: Version, ) -> Result { // Start a handshake process. @@ -467,20 +467,12 @@ fn share_eph_pubkey( protocol_version.decode_initial_handshake(&buf) } -/// Sign the challenge with the local private key -fn sign_challenge( - challenge: &[u8; 32], - local_privkey: &dyn Signer, -) -> Result { - local_privkey.try_sign(challenge).map_err(Error::signature) -} - // TODO(ismail): change from DecodeError to something more generic // this can also fail while writing / sending fn share_auth_signature( sc: &mut SecretConnection, - pubkey: &ed25519::PublicKey, - local_signature: &ed25519::Signature, + pubkey: &ed25519_consensus::VerificationKey, + local_signature: &ed25519_consensus::Signature, ) -> Result { let buf = sc .protocol_version diff --git a/p2p/src/secret_connection/amino_types.rs b/p2p/src/secret_connection/amino_types.rs index bd2c0691f..db36a637a 100644 --- a/p2p/src/secret_connection/amino_types.rs +++ b/p2p/src/secret_connection/amino_types.rs @@ -2,7 +2,6 @@ use crate::error::Error; use core::convert::TryFrom; -use ed25519_dalek as ed25519; use prost_derive::Message; use tendermint_proto as proto; @@ -22,13 +21,16 @@ pub struct AuthSigMessage { } impl AuthSigMessage { - pub fn new(pub_key: &ed25519::PublicKey, sig: &ed25519::Signature) -> Self { + pub fn new( + pub_key: &ed25519_consensus::VerificationKey, + sig: &ed25519_consensus::Signature, + ) -> Self { let mut pub_key_bytes = Vec::from(PUB_KEY_ED25519_AMINO_PREFIX); - pub_key_bytes.extend_from_slice(pub_key.as_ref()); + pub_key_bytes.extend_from_slice(pub_key.as_bytes()); Self { pub_key: pub_key_bytes, - sig: sig.as_ref().to_vec(), + sig: sig.to_bytes().to_vec(), } } } diff --git a/p2p/src/secret_connection/protocol.rs b/p2p/src/secret_connection/protocol.rs index 1e672a872..72c8066be 100644 --- a/p2p/src/secret_connection/protocol.rs +++ b/p2p/src/secret_connection/protocol.rs @@ -2,7 +2,6 @@ use std::convert::TryInto; -use ed25519_dalek as ed25519; use prost::Message as _; use x25519_dalek::PublicKey as EphemeralPublic; @@ -113,8 +112,8 @@ impl Version { #[must_use] pub fn encode_auth_signature( self, - pub_key: &ed25519::PublicKey, - signature: &ed25519::Signature, + pub_key: &ed25519_consensus::VerificationKey, + signature: &ed25519_consensus::Signature, ) -> Vec { if self.is_protobuf() { // Protobuf `AuthSigMessage` @@ -126,7 +125,7 @@ impl Version { let msg = proto::p2p::AuthSigMessage { pub_key: Some(pub_key), - sig: signature.as_ref().to_vec(), + sig: signature.to_bytes().to_vec(), }; let mut buf = Vec::new(); @@ -168,8 +167,8 @@ impl Version { #[cfg(feature = "amino")] fn encode_auth_signature_amino( self, - pub_key: &ed25519::PublicKey, - signature: &ed25519::Signature, + pub_key: &ed25519_consensus::VerificationKey, + signature: &ed25519_consensus::Signature, ) -> Vec { // Legacy Amino encoded `AuthSigMessage` let msg = amino_types::AuthSigMessage::new(pub_key, signature); @@ -184,8 +183,8 @@ impl Version { #[cfg(not(feature = "amino"))] fn encode_auth_signature_amino( self, - _: &ed25519::PublicKey, - _: &ed25519::Signature, + _: &ed25519_consensus::VerificationKey, + _: &ed25519_consensus::Signature, ) -> Vec { panic!("attempted to encode auth signature using amino, but 'amino' feature is not present") } diff --git a/p2p/src/secret_connection/public_key.rs b/p2p/src/secret_connection/public_key.rs index 5d3b43d5e..8fe849311 100644 --- a/p2p/src/secret_connection/public_key.rs +++ b/p2p/src/secret_connection/public_key.rs @@ -1,15 +1,17 @@ //! Secret Connection peer public keys -use ed25519_dalek as ed25519; use sha2::{digest::Digest, Sha256}; -use std::fmt::{self, Display}; +use std::{ + convert::TryFrom, + fmt::{self, Display}, +}; use tendermint::{error::Error, node}; /// Secret Connection peer public keys (signing, presently Ed25519-only) #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum PublicKey { /// Ed25519 Secret Connection Keys - Ed25519(ed25519::PublicKey), + Ed25519(ed25519_consensus::VerificationKey), } impl PublicKey { @@ -19,14 +21,14 @@ impl PublicKey { /// /// * if the bytes given are invalid pub fn from_raw_ed25519(bytes: &[u8]) -> Result { - ed25519::PublicKey::from_bytes(bytes) + ed25519_consensus::VerificationKey::try_from(bytes) .map(Self::Ed25519) - .map_err(Error::signature) + .map_err(|_| Error::signature()) } /// Get Ed25519 public key #[must_use] - pub const fn ed25519(self) -> Option { + pub const fn ed25519(self) -> Option { match self { Self::Ed25519(pk) => Some(pk), } @@ -53,14 +55,14 @@ impl Display for PublicKey { } } -impl From<&ed25519::Keypair> for PublicKey { - fn from(sk: &ed25519::Keypair) -> Self { - Self::Ed25519(sk.public) +impl From<&ed25519_consensus::SigningKey> for PublicKey { + fn from(sk: &ed25519_consensus::SigningKey) -> Self { + Self::Ed25519(sk.verification_key()) } } -impl From for PublicKey { - fn from(pk: ed25519::PublicKey) -> Self { +impl From for PublicKey { + fn from(pk: ed25519_consensus::VerificationKey) -> Self { Self::Ed25519(pk) } } diff --git a/pbt-gen/src/time.rs b/pbt-gen/src/time.rs index 2046df0ba..3ec1bac7f 100644 --- a/pbt-gen/src/time.rs +++ b/pbt-gen/src/time.rs @@ -21,7 +21,6 @@ pub const MAX_NANO_SECS: u32 = 999_999_999u32; /// let timestamp = pbt_gen::time::min_time().unix_timestamp_nanos(); /// assert!(OffsetDateTime::from_unix_timestamp_nanos(timestamp).is_ok()); /// assert!(OffsetDateTime::from_unix_timestamp_nanos(timestamp - 1).is_err()); -/// /// ``` pub fn min_time() -> OffsetDateTime { Date::MIN.midnight().assume_utc() @@ -49,7 +48,6 @@ pub fn max_time() -> OffsetDateTime { /// Google's well-known [`Timestamp`] protobuf message format. /// /// [`Timestamp`]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp -/// pub const fn min_protobuf_time() -> OffsetDateTime { datetime!(0001-01-01 00:00:00 UTC) } @@ -58,7 +56,6 @@ pub const fn min_protobuf_time() -> OffsetDateTime { /// Google's well-known [`Timestamp`] protobuf message format. /// /// [`Timestamp`]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp -/// pub const fn max_protobuf_time() -> OffsetDateTime { datetime!(9999-12-31 23:59:59.999999999 UTC) } @@ -248,7 +245,6 @@ prop_compose! { /// Google's well-known [`Timestamp`] protobuf message format. /// /// [`Timestamp`]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp -/// pub fn arb_protobuf_safe_rfc3339_timestamp() -> impl Strategy { arb_rfc3339_timestamp().prop_filter("timestamp out of protobuf range", |ts| { let t = OffsetDateTime::parse(ts, &Rfc3339).unwrap(); diff --git a/proto/src/serializers/timestamp.rs b/proto/src/serializers/timestamp.rs index 6904bc9fc..ab443f3ab 100644 --- a/proto/src/serializers/timestamp.rs +++ b/proto/src/serializers/timestamp.rs @@ -90,7 +90,6 @@ pub fn to_rfc3339_nanos(t: OffsetDateTime) -> String { /// /// [`Display`]: core::fmt::Display /// [`Debug`]: core::fmt::Debug -/// pub fn fmt_as_rfc3339_nanos(t: OffsetDateTime, f: &mut impl fmt::Write) -> fmt::Result { let t = t.to_offset(offset!(UTC)); let nanos = t.nanosecond(); diff --git a/tendermint/Cargo.toml b/tendermint/Cargo.toml index ceb207ae9..4a3f90b00 100644 --- a/tendermint/Cargo.toml +++ b/tendermint/Cargo.toml @@ -36,7 +36,7 @@ crate-type = ["cdylib", "rlib"] async-trait = { version = "0.1", default-features = false } bytes = { version = "1.0", default-features = false, features = ["serde"] } ed25519 = { version = "1.3", default-features = false } -ed25519-dalek = { version = "1", default-features = false, features = ["u64_backend"] } +ed25519-consensus = { version = "1.2", default-features = false } futures = { version = "0.3", default-features = false } num-traits = { version = "0.2", default-features = false } once_cell = { version = "1.3", default-features = false } diff --git a/tendermint/src/account.rs b/tendermint/src/account.rs index 9eaf6219a..7c2fbc385 100644 --- a/tendermint/src/account.rs +++ b/tendermint/src/account.rs @@ -162,7 +162,7 @@ mod tests { let id_bytes = Id::from_str(id_hex).expect("expected id_hex to decode properly"); // get id for pubkey - let pubkey = Ed25519::from_bytes(pubkey_bytes).unwrap(); + let pubkey = Ed25519::try_from(&pubkey_bytes[..]).unwrap(); let id = Id::from(pubkey); assert_eq!(id_bytes.ct_eq(&id).unwrap_u8(), 1); diff --git a/tendermint/src/error.rs b/tendermint/src/error.rs index a6be0a514..27d199564 100644 --- a/tendermint/src/error.rs +++ b/tendermint/src/error.rs @@ -208,8 +208,7 @@ define_error! { |_| { format_args!("subtle encoding error") }, Signature - [ DisplayOnly ] - |_| { format_args!("signature error") }, + |_| { "signature error" }, TrustThresholdTooLarge |_| { "trust threshold is too large (must be <= 1)" }, diff --git a/tendermint/src/private_key.rs b/tendermint/src/private_key.rs index 7d4280bfc..0c0989f54 100644 --- a/tendermint/src/private_key.rs +++ b/tendermint/src/private_key.rs @@ -1,13 +1,16 @@ //! Cryptographic private keys -pub use ed25519_dalek::{Keypair as Ed25519, EXPANDED_SECRET_KEY_LENGTH as ED25519_KEYPAIR_SIZE}; +pub use ed25519_consensus::SigningKey as Ed25519; use crate::prelude::*; use crate::public_key::PublicKey; +use ed25519_consensus::VerificationKey; use serde::{de, ser, Deserialize, Serialize}; use subtle_encoding::{Base64, Encoding}; use zeroize::Zeroizing; +pub const ED25519_KEYPAIR_SIZE: usize = 64; + /// Private keys as parsed from configuration files #[derive(Serialize, Deserialize)] #[non_exhaustive] @@ -26,24 +29,28 @@ impl PrivateKey { /// Get the public key associated with this private key pub fn public_key(&self) -> PublicKey { match self { - PrivateKey::Ed25519(private_key) => private_key.public.into(), + PrivateKey::Ed25519(signing_key) => PublicKey::Ed25519(signing_key.verification_key()), } } /// If applicable, borrow the Ed25519 keypair - pub fn ed25519_keypair(&self) -> Option<&Ed25519> { + pub fn ed25519_signing_key(&self) -> Option<&Ed25519> { match self { - PrivateKey::Ed25519(keypair) => Some(keypair), + PrivateKey::Ed25519(signing_key) => Some(signing_key), } } } /// Serialize an Ed25519 keypair as Base64 -fn serialize_ed25519_keypair(keypair: &Ed25519, serializer: S) -> Result +fn serialize_ed25519_keypair(signing_key: &Ed25519, serializer: S) -> Result where S: ser::Serializer, { - let keypair_bytes = Zeroizing::new(keypair.to_bytes()); + // Tendermint uses a serialization format inherited from Go that includes + // a cached copy of the public key as the second half. + let mut keypair_bytes = Zeroizing::new([0u8; ED25519_KEYPAIR_SIZE]); + keypair_bytes[0..32].copy_from_slice(signing_key.as_bytes()); + keypair_bytes[32..64].copy_from_slice(signing_key.verification_key().as_bytes()); Zeroizing::new(String::from_utf8(Base64::default().encode(&keypair_bytes[..])).unwrap()) .serialize(serializer) } @@ -64,5 +71,17 @@ where return Err(D::Error::custom("invalid Ed25519 keypair size")); } - Ed25519::from_bytes(&*keypair_bytes).map_err(D::Error::custom) + // Tendermint uses a serialization format inherited from Go that includes a + // cached copy of the public key as the second half. This is somewhat + // dangerous, since there's no validation that the two parts are consistent + // with each other, so we ignore the second half and just check consistency + // with the re-derived data. + let signing_key = Ed25519::try_from(&keypair_bytes[0..32]) + .map_err(|_| D::Error::custom("invalid signing key"))?; + let verification_key = VerificationKey::from(&signing_key); + if &keypair_bytes[32..64] != verification_key.as_bytes() { + return Err(D::Error::custom("keypair mismatch")); + } + + Ok(signing_key) } diff --git a/tendermint/src/public_key.rs b/tendermint/src/public_key.rs index b8a515880..19ff14763 100644 --- a/tendermint/src/public_key.rs +++ b/tendermint/src/public_key.rs @@ -1,6 +1,6 @@ //! Public keys used in Tendermint networks -pub use ed25519_dalek::PublicKey as Ed25519; +pub use ed25519_consensus::VerificationKey as Ed25519; #[cfg(feature = "secp256k1")] pub use k256::ecdsa::VerifyingKey as Secp256k1; @@ -14,12 +14,14 @@ use crate::{error::Error, signature::Signature}; use core::convert::TryFrom; use core::{cmp::Ordering, fmt, ops::Deref, str::FromStr}; use serde::{de, ser, Deserialize, Serialize}; -use signature::Verifier as _; use subtle_encoding::{base64, bech32, hex}; use tendermint_proto::crypto::public_key::Sum; use tendermint_proto::crypto::PublicKey as RawPublicKey; use tendermint_proto::Protobuf; +#[cfg(feature = "secp256k1")] +use signature::Verifier as _; + // Note:On the golang side this is generic in the sense that it could everything that implements // github.com/tendermint/tendermint/crypto.PubKey // While this is meant to be used with different key-types, it currently only uses a PubKeyEd25519 @@ -106,7 +108,9 @@ impl PublicKey { /// From raw Ed25519 public key bytes pub fn from_raw_ed25519(bytes: &[u8]) -> Option { - Ed25519::from_bytes(bytes).map(Into::into).ok() + Ed25519::try_from(bytes) + .map(|vk| PublicKey::Ed25519(vk)) + .ok() } /// Get Ed25519 public key @@ -132,15 +136,14 @@ impl PublicKey { pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> { match self { PublicKey::Ed25519(pk) => { - match ed25519_dalek::Signature::try_from(signature.as_bytes()) { - Ok(sig) => pk.verify(msg, &sig).map_err(|_| { + match ed25519_consensus::Signature::try_from(signature.as_bytes()) { + Ok(sig) => pk.verify(&sig, msg).map_err(|_| { Error::signature_invalid( "Ed25519 signature verification failed".to_string(), ) }), - Err(e) => Err(Error::signature_invalid(format!( - "invalid Ed25519 signature: {}", - e + Err(_) => Err(Error::signature_invalid(format!( + "Could not parse Ed25519 signature", ))), } } @@ -360,7 +363,7 @@ where use de::Error; let encoded = String::deserialize(deserializer)?; let bytes = base64::decode(&encoded).map_err(D::Error::custom)?; - Ed25519::from_bytes(&bytes).map_err(D::Error::custom) + Ed25519::try_from(&bytes[..]).map_err(|_| D::Error::custom("invalid Ed25519 key")) } #[cfg(feature = "secp256k1")] diff --git a/tendermint/src/signature.rs b/tendermint/src/signature.rs index 603745237..955da8e29 100644 --- a/tendermint/src/signature.rs +++ b/tendermint/src/signature.rs @@ -88,8 +88,14 @@ impl AsRef<[u8]> for Signature { } impl From for Signature { - fn from(pk: Ed25519Signature) -> Signature { - Self(pk.as_ref().to_vec()) + fn from(sig: Ed25519Signature) -> Signature { + Self(sig.as_ref().to_vec()) + } +} + +impl From for Signature { + fn from(sig: ed25519_consensus::Signature) -> Signature { + Self(sig.to_bytes().to_vec()) } } diff --git a/tendermint/src/time.rs b/tendermint/src/time.rs index ac53be2c8..9fd9a7432 100644 --- a/tendermint/src/time.rs +++ b/tendermint/src/time.rs @@ -30,7 +30,6 @@ use crate::error::Error; /// This reproduces the behavior of Go's `time.RFC3339Nano` format. /// /// [specification]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp -/// // For memory efficiency, the inner member is `PrimitiveDateTime`, with assumed // UTC offset. The `assume_utc` method is used to get the operational // `OffsetDateTime` value. diff --git a/tendermint/src/validator.rs b/tendermint/src/validator.rs index 67083361c..b4e17b6e5 100644 --- a/tendermint/src/validator.rs +++ b/tendermint/src/validator.rs @@ -268,7 +268,7 @@ impl From<&Info> for SimpleValidator { fn from(info: &Info) -> SimpleValidator { let sum = match &info.pub_key { PublicKey::Ed25519(pk) => Some(tendermint_proto::crypto::public_key::Sum::Ed25519( - pk.as_bytes().to_vec(), + pk.as_ref().to_vec(), )), #[cfg(feature = "secp256k1")] PublicKey::Secp256k1(pk) => Some(tendermint_proto::crypto::public_key::Sum::Secp256k1( diff --git a/test/Cargo.toml b/test/Cargo.toml index 1c63c3a5a..be2013552 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -14,10 +14,10 @@ authors = ["Alexander Simmerl "] test = true [dev-dependencies] -ed25519-dalek = { version = "1", default-features = false, features = ["rand"] } +ed25519-consensus = { version = "1.2", default-features = false } flex-error = { version = "0.4.4", default-features = false } flume = { version = "0.10", default-features = false } -rand_core = { version = "0.5", default-features = false, features = ["std"] } +rand_core = { version = "0.6", default-features = false, features = ["std"] } readwrite = { version = "^0.1.1", default-features = false } subtle-encoding = { version = "0.5", default-features = false } x25519-dalek = { version = "1.1", default-features = false } diff --git a/test/src/test/unit/p2p/secret_connection.rs b/test/src/test/unit/p2p/secret_connection.rs index 797a29d60..2d5dfd66b 100644 --- a/test/src/test/unit/p2p/secret_connection.rs +++ b/test/src/test/unit/p2p/secret_connection.rs @@ -3,7 +3,7 @@ use std::io::Write as _; use std::net::{TcpListener, TcpStream}; use std::thread; -use ed25519_dalek::{self as ed25519}; +use ed25519_consensus; use rand_core::OsRng; use x25519_dalek::PublicKey as EphemeralPublic; @@ -64,7 +64,7 @@ fn test_read_write_single_message() { #[test] fn test_evil_peer_shares_invalid_eph_key() { let mut csprng = OsRng {}; - let local_privkey: ed25519::Keypair = ed25519::Keypair::generate(&mut csprng); + let local_privkey = ed25519_consensus::SigningKey::new(&mut csprng); let (mut h, _) = Handshake::new(local_privkey, Version::V0_34); let bytes: [u8; 32] = [0; 32]; let res = h.got_key(EphemeralPublic::from(bytes)); @@ -74,7 +74,7 @@ fn test_evil_peer_shares_invalid_eph_key() { #[test] fn test_evil_peer_shares_invalid_auth_sig() { let mut csprng = OsRng {}; - let local_privkey: ed25519::Keypair = ed25519::Keypair::generate(&mut csprng); + let local_privkey = ed25519_consensus::SigningKey::new(&mut csprng); let (mut h, _) = Handshake::new(local_privkey, Version::V0_34); let res = h.got_key(EphemeralPublic::from(x25519_dalek::X25519_BASEPOINT_BYTES)); assert!(res.is_ok()); @@ -186,6 +186,6 @@ where IoHandler: std::io::Read + std::io::Write + Send + Sync, { let mut csprng = OsRng {}; - let privkey1: ed25519::Keypair = ed25519::Keypair::generate(&mut csprng); + let privkey1 = ed25519_consensus::SigningKey::new(&mut csprng); SecretConnection::new(io_handler, privkey1, Version::V0_34) } diff --git a/testgen/Cargo.toml b/testgen/Cargo.toml index 1b60ad86d..05caf7af9 100644 --- a/testgen/Cargo.toml +++ b/testgen/Cargo.toml @@ -19,7 +19,7 @@ description = """ tendermint = { version = "0.23.0", path = "../tendermint" } serde = { version = "1", default-features = false, features = ["derive"] } serde_json = { version = "1", default-features = false, features = ["std"] } -ed25519-dalek = { version = "1", default-features = false } +ed25519-consensus = { version = "1.2", default-features = false } gumdrop = { version = "0.8.0", default-features = false } simple-error = { version = "0.2.1", default-features = false } tempfile = { version = "3.1.0", default-features = false } diff --git a/testgen/src/helpers.rs b/testgen/src/helpers.rs index 037fb4f6f..d683cf14e 100644 --- a/testgen/src/helpers.rs +++ b/testgen/src/helpers.rs @@ -3,11 +3,7 @@ use serde::de::DeserializeOwned; use simple_error::*; use std::io::{self, Read}; -use tendermint::{ - chain, public_key, - signature::{Signature, Verifier}, - vote, Time, -}; +use tendermint::{chain, public_key, signature::Signature, vote, Time}; /// A macro that generates a complete setter method from a one-liner with necessary information #[macro_export] @@ -51,8 +47,8 @@ pub fn get_vote_sign_bytes(chain_id: chain::Id, vote: &vote::Vote) -> Vec { pub fn verify_signature(verifier: &public_key::Ed25519, msg: &[u8], signature: &Signature) -> bool { use std::convert::TryFrom; - let sig = ed25519_dalek::Signature::try_from(signature.as_bytes()); - sig.and_then(|sig| verifier.verify(msg, &sig)).is_ok() + let sig = ed25519_consensus::Signature::try_from(signature.as_bytes()); + sig.and_then(|sig| verifier.verify(&sig, msg)).is_ok() } pub fn get_time(abs: u64) -> Result { diff --git a/testgen/src/validator.rs b/testgen/src/validator.rs index f67ad3db4..9b5ee28ef 100644 --- a/testgen/src/validator.rs +++ b/testgen/src/validator.rs @@ -1,5 +1,5 @@ use crate::{helpers::*, Generator}; -use ed25519_dalek::SecretKey as Ed25519SecretKey; +use ed25519_consensus::SigningKey as Ed25519SigningKey; use gumdrop::Options; use serde::{Deserialize, Serialize}; use simple_error::*; @@ -47,17 +47,17 @@ impl Validator { bail!("validator identifier is too long") } bytes.extend(vec![0u8; 32 - bytes.len()].iter()); - let secret = require_with!( - Ed25519SecretKey::from_bytes(&bytes).ok(), + let signing_key = require_with!( + Ed25519SigningKey::try_from(&bytes[..]).ok(), "failed to construct a seed from validator identifier" ); - let public = public_key::Ed25519::from(&secret); - Ok(private_key::Ed25519 { secret, public }) + Ok(signing_key) } /// Get public key for this validator companion. pub fn get_public_key(&self) -> Result { - self.get_private_key().map(|keypair| keypair.public) + self.get_private_key() + .map(|secret_key| secret_key.verification_key()) } } @@ -104,10 +104,10 @@ impl Generator for Validator { } fn generate(&self) -> Result { - let keypair = self.get_private_key()?; + let verification_key = self.get_private_key()?.verification_key(); let info = validator::Info { - address: account::Id::from(keypair.public), - pub_key: PublicKey::from(keypair.public), + address: account::Id::from(verification_key), + pub_key: PublicKey::from(verification_key), power: vote::Power::try_from(self.voting_power.unwrap_or(0)).unwrap(), name: None, proposer_priority: validator::ProposerPriority::from( diff --git a/testgen/src/vote.rs b/testgen/src/vote.rs index 4b5ad8d03..3d188e711 100644 --- a/testgen/src/vote.rs +++ b/testgen/src/vote.rs @@ -5,7 +5,7 @@ use simple_error::*; use std::convert::TryFrom; use tendermint::{ block::{self, parts::Header as PartSetHeader}, - signature::{Ed25519Signature, Signature, Signer}, + signature::{Ed25519Signature, Signature}, vote, vote::ValidatorIndex, }; @@ -87,7 +87,7 @@ impl Generator for Vote { None => bail!("failed to generate vote: header is missing"), Some(h) => h, }; - let signer = validator.get_private_key()?; + let signing_key = validator.get_private_key()?; let block_validator = validator.generate()?; let block_header = header.generate()?; let block_id = if self.nil.is_some() { @@ -135,7 +135,7 @@ impl Generator for Vote { }; let sign_bytes = get_vote_sign_bytes(block_header.chain_id, &vote); - vote.signature = Some(signer.sign(sign_bytes.as_slice()).into()); + vote.signature = Some(signing_key.sign(sign_bytes.as_slice()).into()); Ok(vote) }