From ea8a3038a7ac9d49ac89ff996ea74f14ef447a87 Mon Sep 17 00:00:00 2001 From: Miguel Guarniz Date: Thu, 20 Oct 2022 13:52:30 -0400 Subject: [PATCH] Replace prost with protobuf in core --- core/CHANGELOG.md | 6 +++ core/Cargo.toml | 4 +- core/build.rs | 16 ++++--- core/src/identity.rs | 95 ++++++++++++++++++++----------------- core/src/lib.rs | 17 +++---- core/src/peer_record.rs | 41 ++++++++-------- core/src/signed_envelope.rs | 31 +++++------- 7 files changed, 108 insertions(+), 102 deletions(-) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index e996824209c..25263e37307 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.38.0 [unreleased] + +- Remove `prost` and add `protobuf`. See [PR 3050]. + +[PR 3050]: https://github.com/libp2p/rust-libp2p/pull/3050 + # 0.37.0 - Implement `Hash` and `Ord` for `PublicKey`. See [PR 2915]. diff --git a/core/Cargo.toml b/core/Cargo.toml index 027cd6bd824..f3eaff0e6ba 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -28,7 +28,7 @@ multistream-select = { version = "0.12", path = "../misc/multistream-select" } p256 = { version = "0.11.1", default-features = false, features = ["ecdsa"], optional = true } parking_lot = "0.12.0" pin-project = "1.0.0" -prost = "0.11" +protobuf = "3.2" rand = "0.8" rw-stream-sink = { version = "0.3.0", path = "../misc/rw-stream-sink" } sha2 = "0.10.0" @@ -53,7 +53,7 @@ rmp-serde = "1.0" serde_json = "1.0" [build-dependencies] -prost-build = "0.11" +protobuf-codegen = "3.2" [features] secp256k1 = [ "libsecp256k1" ] diff --git a/core/build.rs b/core/build.rs index f0c09f93abf..b0760b44d19 100644 --- a/core/build.rs +++ b/core/build.rs @@ -19,13 +19,17 @@ // DEALINGS IN THE SOFTWARE. fn main() { - prost_build::compile_protos( - &[ + protobuf_codegen::Codegen::new() + .pure() + .includes(&["src"]) + .inputs( + &[ "src/keys.proto", "src/envelope.proto", "src/peer_record.proto", - ], - &["src"], - ) - .unwrap(); + ] + ) + .cargo_out_dir("protos") + .run() + .unwrap() } diff --git a/core/src/identity.rs b/core/src/identity.rs index af5dceb69ee..e2061cf1463 100644 --- a/core/src/identity.rs +++ b/core/src/identity.rs @@ -147,12 +147,14 @@ impl Keypair { /// Encode a private key as protobuf structure. pub fn to_protobuf_encoding(&self) -> Result, DecodingError> { - use prost::Message; + use protobuf::Message; let pk = match self { - Self::Ed25519(data) => keys_proto::PrivateKey { - r#type: keys_proto::KeyType::Ed25519.into(), - data: data.encode().into(), + Self::Ed25519(data) => { + let mut key = keys_proto::PrivateKey::new(); + key.set_Type(keys_proto::KeyType::Ed25519); + key.set_Data(data.encode().into()); + key }, #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] Self::Rsa(_) => { @@ -174,32 +176,33 @@ impl Keypair { } }; - Ok(pk.encode_to_vec()) + Ok(pk.write_to_bytes().map_err(|e| DecodingError::new("Failed to decode.").source(e))?) } /// Decode a private key from a protobuf structure and parse it as a [`Keypair`]. pub fn from_protobuf_encoding(bytes: &[u8]) -> Result { - use prost::Message; + use protobuf::Message; + use protobuf::Enum; - let mut private_key = keys_proto::PrivateKey::decode(bytes) + let mut private_key = keys_proto::PrivateKey::parse_from_bytes(bytes) .map_err(|e| DecodingError::new("Protobuf").source(e)) .map(zeroize::Zeroizing::new)?; - let key_type = keys_proto::KeyType::from_i32(private_key.r#type).ok_or_else(|| { - DecodingError::new(format!("unknown key type: {}", private_key.r#type)) + let key_type = keys_proto::KeyType::from_i32(private_key.Type().value()).ok_or_else(|| { + DecodingError::new(format!("unknown key type: {:?}", private_key.Type())) })?; match key_type { keys_proto::KeyType::Ed25519 => { - ed25519::Keypair::decode(&mut private_key.data).map(Keypair::Ed25519) + ed25519::Keypair::decode(&mut private_key.mut_Data()).map(Keypair::Ed25519) } - keys_proto::KeyType::Rsa => Err(DecodingError::new( + keys_proto::KeyType::RSA => Err(DecodingError::new( "Decoding RSA key from Protobuf is unsupported.", )), keys_proto::KeyType::Secp256k1 => Err(DecodingError::new( "Decoding Secp256k1 key from Protobuf is unsupported.", )), - keys_proto::KeyType::Ecdsa => Err(DecodingError::new( + keys_proto::KeyType::ECDSA => Err(DecodingError::new( "Decoding ECDSA key from Protobuf is unsupported.", )), } @@ -208,8 +211,8 @@ impl Keypair { impl zeroize::Zeroize for keys_proto::PrivateKey { fn zeroize(&mut self) { - self.r#type.zeroize(); - self.data.zeroize(); + use protobuf::Message; + self.clear() } } @@ -251,23 +254,19 @@ impl PublicKey { /// Encode the public key into a protobuf structure for storage or /// exchange with other nodes. pub fn to_protobuf_encoding(&self) -> Vec { - use prost::Message; + use protobuf::Message; let public_key = keys_proto::PublicKey::from(self); - let mut buf = Vec::with_capacity(public_key.encoded_len()); - public_key - .encode(&mut buf) - .expect("Vec provides capacity as needed"); - buf + public_key.write_to_bytes().expect("Encoding failed.") } /// Decode a public key from a protobuf structure, e.g. read from storage /// or received from another node. pub fn from_protobuf_encoding(bytes: &[u8]) -> Result { - use prost::Message; + use protobuf::Message; - let pubkey = keys_proto::PublicKey::decode(bytes) + let pubkey = keys_proto::PublicKey::parse_from_bytes(bytes) .map_err(|e| DecodingError::new("Protobuf").source(e))?; pubkey.try_into() @@ -282,24 +281,32 @@ impl PublicKey { impl From<&PublicKey> for keys_proto::PublicKey { fn from(key: &PublicKey) -> Self { match key { - PublicKey::Ed25519(key) => keys_proto::PublicKey { - r#type: keys_proto::KeyType::Ed25519 as i32, - data: key.encode().to_vec(), + PublicKey::Ed25519(key) => { + let mut pubkey = keys_proto::PublicKey::new(); + pubkey.set_Type(keys_proto::KeyType::Ed25519); + pubkey.set_Data(key.encode().to_vec()); + pubkey }, #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - PublicKey::Rsa(key) => keys_proto::PublicKey { - r#type: keys_proto::KeyType::Rsa as i32, - data: key.encode_x509(), + PublicKey::Rsa(key) => { + let mut pubkey = keys_proto::PublicKey::new(); + pubkey.set_Type(keys_proto::KeyType::Rsa); + pubkey.set_Data(key.encode_x509()); + pubkey }, #[cfg(feature = "secp256k1")] - PublicKey::Secp256k1(key) => keys_proto::PublicKey { - r#type: keys_proto::KeyType::Secp256k1 as i32, - data: key.encode().to_vec(), + PublicKey::Secp256k1(key) => { + let mut pubkey = keys_proto::PublicKey::new(); + pubkey.set_Type(keys_proto::KeyType::Secp256k1); + pubkey.set_Data(key.encode().to_vec()); + pubkey }, #[cfg(feature = "ecdsa")] - PublicKey::Ecdsa(key) => keys_proto::PublicKey { - r#type: keys_proto::KeyType::Ecdsa as i32, - data: key.encode_der(), + PublicKey::Ecdsa(key) => { + let mut pubkey = keys_proto::PublicKey::new(); + pubkey.set_Type(keys_proto::KeyType::ECDSA); + pubkey.set_Data(key.encode_der()); + pubkey }, } } @@ -309,25 +316,27 @@ impl TryFrom for PublicKey { type Error = DecodingError; fn try_from(pubkey: keys_proto::PublicKey) -> Result { - let key_type = keys_proto::KeyType::from_i32(pubkey.r#type) - .ok_or_else(|| DecodingError::new(format!("unknown key type: {}", pubkey.r#type)))?; + use protobuf::Enum; + + let key_type = keys_proto::KeyType::from_i32(pubkey.Type().value()) + .ok_or_else(|| DecodingError::new(format!("unknown key type: {}", pubkey.Type().value())))?; match key_type { keys_proto::KeyType::Ed25519 => { - ed25519::PublicKey::decode(&pubkey.data).map(PublicKey::Ed25519) + ed25519::PublicKey::decode(&pubkey.Data()).map(PublicKey::Ed25519) } #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] keys_proto::KeyType::Rsa => { - rsa::PublicKey::decode_x509(&pubkey.data).map(PublicKey::Rsa) + rsa::PublicKey::decode_x509(&pubkey.Data()).map(PublicKey::Rsa) } #[cfg(any(not(feature = "rsa"), target_arch = "wasm32"))] - keys_proto::KeyType::Rsa => { + keys_proto::KeyType::RSA => { log::debug!("support for RSA was disabled at compile-time"); Err(DecodingError::new("Unsupported")) } #[cfg(feature = "secp256k1")] keys_proto::KeyType::Secp256k1 => { - secp256k1::PublicKey::decode(&pubkey.data).map(PublicKey::Secp256k1) + secp256k1::PublicKey::decode(&pubkey.Data()).map(PublicKey::Secp256k1) } #[cfg(not(feature = "secp256k1"))] keys_proto::KeyType::Secp256k1 => { @@ -335,11 +344,11 @@ impl TryFrom for PublicKey { Err(DecodingError::new("Unsupported")) } #[cfg(feature = "ecdsa")] - keys_proto::KeyType::Ecdsa => { - ecdsa::PublicKey::decode_der(&pubkey.data).map(PublicKey::Ecdsa) + keys_proto::KeyType::ECDSA => { + ecdsa::PublicKey::decode_der(&pubkey.Data()).map(PublicKey::Ecdsa) } #[cfg(not(feature = "ecdsa"))] - keys_proto::KeyType::Ecdsa => { + keys_proto::KeyType::ECDSA => { log::debug!("support for ECDSA was disabled at compile-time"); Err(DecodingError::new("Unsupported")) } diff --git a/core/src/lib.rs b/core/src/lib.rs index 88c6cc0df7c..543a0c5ac77 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -37,19 +37,14 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -#[allow(clippy::derive_partial_eq_without_eq)] -mod keys_proto { - include!(concat!(env!("OUT_DIR"), "/keys_proto.rs")); -} - -mod envelope_proto { - include!(concat!(env!("OUT_DIR"), "/envelope_proto.rs")); +mod protos { + include!(concat!(env!("OUT_DIR"), "/protos/mod.rs")); } - #[allow(clippy::derive_partial_eq_without_eq)] -mod peer_record_proto { - include!(concat!(env!("OUT_DIR"), "/peer_record_proto.rs")); -} +use protos::keys as keys_proto; +use protos::envelope as envelope_proto; +#[allow(clippy::derive_partial_eq_without_eq)] +use protos::peer_record as peer_record_proto; /// Multi-address re-export. pub use multiaddr; diff --git a/core/src/peer_record.rs b/core/src/peer_record.rs index d0d8e21a4b5..21dc18a02ec 100644 --- a/core/src/peer_record.rs +++ b/core/src/peer_record.rs @@ -30,11 +30,11 @@ impl PeerRecord { /// /// If this function succeeds, the [`SignedEnvelope`] contained a peer record with a valid signature and can hence be considered authenticated. pub fn from_signed_envelope(envelope: SignedEnvelope) -> Result { - use prost::Message; + use protobuf::Message; let (payload, signing_key) = envelope.payload_and_signing_key(String::from(DOMAIN_SEP), PAYLOAD_TYPE.as_bytes())?; - let record = peer_record_proto::PeerRecord::decode(payload)?; + let record = peer_record_proto::PeerRecord::parse_from_bytes(payload).map_err(|e| FromEnvelopeError::from(e))?; let peer_id = PeerId::from_bytes(&record.peer_id)?; @@ -61,7 +61,7 @@ impl PeerRecord { /// /// This is the same key that is used for authenticating every libp2p connection of your application, i.e. what you use when setting up your [`crate::transport::Transport`]. pub fn new(key: &Keypair, addresses: Vec) -> Result { - use prost::Message; + use protobuf::Message; let seq = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) @@ -70,22 +70,19 @@ impl PeerRecord { let peer_id = key.public().to_peer_id(); let payload = { - let record = peer_record_proto::PeerRecord { - peer_id: peer_id.to_bytes(), - seq, - addresses: addresses - .iter() - .map(|m| peer_record_proto::peer_record::AddressInfo { - multiaddr: m.to_vec(), - }) - .collect(), - }; - - let mut buf = Vec::with_capacity(record.encoded_len()); - record - .encode(&mut buf) - .expect("Vec provides capacity as needed"); - buf + let mut record = peer_record_proto::PeerRecord::new(); + record.peer_id = peer_id.to_bytes(); + record.seq = seq; + record.addresses = addresses + .iter() + .map(|m| { + let mut addr_info = peer_record_proto::peer_record::AddressInfo::new(); + addr_info.multiaddr = m.to_vec(); + addr_info + }) + .collect(); + + record.write_to_bytes().expect("Encoding to succeed.") }; let envelope = SignedEnvelope::new( @@ -129,7 +126,7 @@ pub enum FromEnvelopeError { /// Failed to extract the payload from the envelope. BadPayload(signed_envelope::ReadPayloadError), /// Failed to decode the provided bytes as a [`PeerRecord`]. - InvalidPeerRecord(prost::DecodeError), + InvalidPeerRecord(protobuf::Error), /// Failed to decode the peer ID. InvalidPeerId(multihash::Error), /// The signer of the envelope is different than the peer id in the record. @@ -144,8 +141,8 @@ impl From for FromEnvelopeError { } } -impl From for FromEnvelopeError { - fn from(e: prost::DecodeError) -> Self { +impl From for FromEnvelopeError { + fn from(e: protobuf::Error) -> Self { Self::InvalidPeerRecord(e) } } diff --git a/core/src/signed_envelope.rs b/core/src/signed_envelope.rs index 33bfdf2d4f4..63634edf7ea 100644 --- a/core/src/signed_envelope.rs +++ b/core/src/signed_envelope.rs @@ -73,32 +73,27 @@ impl SignedEnvelope { /// Encode this [`SignedEnvelope`] using the protobuf encoding specified in the RFC. pub fn into_protobuf_encoding(self) -> Vec { - use prost::Message; + use protobuf::Message; - let envelope = crate::envelope_proto::Envelope { - public_key: Some((&self.key).into()), - payload_type: self.payload_type, - payload: self.payload, - signature: self.signature, - }; + let mut envelope = crate::envelope_proto::Envelope::new(); + envelope.public_key = protobuf::MessageField::some((&self.key).into()); + envelope.payload_type = self.payload_type; + envelope.payload = self.payload; + envelope.signature = self.signature; - let mut buf = Vec::with_capacity(envelope.encoded_len()); - envelope - .encode(&mut buf) - .expect("Vec provides capacity as needed"); - - buf + envelope.write_to_bytes().expect("Encoding to succeed.") } /// Decode a [`SignedEnvelope`] using the protobuf encoding specified in the RFC. pub fn from_protobuf_encoding(bytes: &[u8]) -> Result { - use prost::Message; + use protobuf::Message; - let envelope = crate::envelope_proto::Envelope::decode(bytes)?; + let envelope = crate::envelope_proto::Envelope::parse_from_bytes(bytes)?; Ok(Self { key: envelope .public_key + .into_option() .ok_or(DecodingError::MissingPublicKey)? .try_into()?, payload_type: envelope.payload_type, @@ -143,15 +138,15 @@ fn signature_payload(domain_separation: String, payload_type: &[u8], payload: &[ #[derive(Debug)] pub enum DecodingError { /// Decoding the provided bytes as a signed envelope failed. - InvalidEnvelope(prost::DecodeError), + InvalidEnvelope(protobuf::Error), /// The public key in the envelope could not be converted to our internal public key type. InvalidPublicKey(identity::error::DecodingError), /// The public key in the envelope could not be converted to our internal public key type. MissingPublicKey, } -impl From for DecodingError { - fn from(e: prost::DecodeError) -> Self { +impl From for DecodingError { + fn from(e: protobuf::Error) -> Self { Self::InvalidEnvelope(e) } }