From dfa7bd6b579d1e0e92e7c8df3ba068a8763bdfec Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Thu, 30 Mar 2023 19:47:35 +0200 Subject: [PATCH] refactor: don't depend on multihash features All we need from the multihash is for it to be a data structure that we pass around. We only ever use the identity "hasher" and the sha256 hasher. Those are easily implemented without depending the (fairly heavy) machinery in `multihash`. Unfortunately, this patch by itself does not yet lighten our dependency tree because `multiaddr` activates those features unconditionally. I opened a companion PR for this: https://github.com/multiformats/rust-multiaddr/pull/77. https://github.com/multiformats/rust-multiaddr/pull/77 is another breaking change and we are trying to delay those at the moment. However, it will (hopefully) land eventually which should then be much easier to implement. Fixes #3276. Pull-Request: #3514. --- Cargo.lock | 3 +- core/Cargo.toml | 2 +- identity/Cargo.toml | 4 +-- identity/src/keypair.rs | 8 +++++ identity/src/peer_id.rs | 31 ++++++++++++------- protocols/kad/src/behaviour/test.rs | 11 ++++--- protocols/kad/src/kbucket/key.rs | 4 +-- protocols/kad/src/lib.rs | 4 +++ protocols/kad/src/query/peers/closest.rs | 12 +++---- .../kad/src/query/peers/closest/disjoint.rs | 7 ++--- protocols/kad/src/record.rs | 4 +-- protocols/kad/src/record/store/memory.rs | 5 +-- transports/webrtc/Cargo.toml | 3 +- transports/webrtc/src/tokio/fingerprint.rs | 27 +++++++--------- 14 files changed, 71 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 51cfe03f..7831ab47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2945,6 +2945,7 @@ dependencies = [ "rand 0.8.5", "rcgen 0.9.3", "serde", + "sha2 0.10.6", "stun", "thiserror", "tinytemplate", @@ -3214,13 +3215,11 @@ checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" dependencies = [ "arbitrary", "core2", - "digest 0.10.6", "multihash-derive", "quickcheck", "rand 0.8.5", "serde", "serde-big-array", - "sha2 0.10.6", "unsigned-varint", ] diff --git a/core/Cargo.toml b/core/Cargo.toml index f05c912a..75c37ab3 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -19,7 +19,7 @@ instant = "0.1.11" libp2p-identity = { version = "0.1", path = "../identity", features = ["peerid", "ed25519"] } log = "0.4" multiaddr = { version = "0.17.0" } -multihash = { version = "0.17.0", default-features = false, features = ["std", "multihash-impl", "identity", "sha2"] } +multihash = { version = "0.17.0", default-features = false, features = ["std"] } multistream-select = { version = "0.12.1", path = "../misc/multistream-select" } once_cell = "1.17.1" parking_lot = "0.12.0" diff --git a/identity/Cargo.toml b/identity/Cargo.toml index 7d910bce..e2764e1e 100644 --- a/identity/Cargo.toml +++ b/identity/Cargo.toml @@ -18,7 +18,7 @@ ed25519-dalek = { version = "1.0.1", optional = true } libsecp256k1 = { version = "0.7.0", optional = true } log = "0.4" multiaddr = { version = "0.17.0", optional = true } -multihash = { version = "0.17.0", default-features = false, features = ["std", "multihash-impl", "identity", "sha2"], optional = true } +multihash = { version = "0.17.0", default-features = false, features = ["std"], optional = true } p256 = { version = "0.12", default-features = false, features = ["ecdsa", "std"], optional = true } prost = { version = "0.11", optional = true } quick-protobuf = "0.8.1" @@ -38,7 +38,7 @@ secp256k1 = [ "libsecp256k1", "asn1_der", "prost", "rand", "sha2", "zeroize" ] ecdsa = [ "p256", "prost", "rand", "void", "zeroize", "sec1" ] rsa = [ "dep:ring", "asn1_der", "prost", "rand", "zeroize" ] ed25519 = [ "ed25519-dalek", "prost", "rand", "zeroize" ] -peerid = [ "multihash", "multiaddr", "bs58", "rand", "thiserror" ] +peerid = [ "multihash", "multiaddr", "bs58", "rand", "thiserror", "sha2" ] [dev-dependencies] quickcheck = { package = "quickcheck-ext", path = "../misc/quickcheck-ext" } diff --git a/identity/src/keypair.rs b/identity/src/keypair.rs index e7e89ca5..0e4cce68 100644 --- a/identity/src/keypair.rs +++ b/identity/src/keypair.rs @@ -110,6 +110,7 @@ impl Keypair { #[cfg(feature = "ed25519")] pub fn into_ed25519(self) -> Option { #[allow(deprecated)] + #[allow(unreachable_patterns)] match self { Keypair::Ed25519(inner) => Some(inner), _ => None, @@ -119,6 +120,7 @@ impl Keypair { #[cfg(feature = "secp256k1")] pub fn into_secp256k1(self) -> Option { #[allow(deprecated)] + #[allow(unreachable_patterns)] match self { Keypair::Secp256k1(inner) => Some(inner), _ => None, @@ -128,6 +130,7 @@ impl Keypair { #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] pub fn into_rsa(self) -> Option { #[allow(deprecated)] + #[allow(unreachable_patterns)] match self { Keypair::Rsa(inner) => Some(inner), _ => None, @@ -137,6 +140,7 @@ impl Keypair { #[cfg(feature = "ecdsa")] pub fn into_ecdsa(self) -> Option { #[allow(deprecated)] + #[allow(unreachable_patterns)] match self { Keypair::Ecdsa(inner) => Some(inner), _ => None, @@ -354,6 +358,7 @@ impl PublicKey { #[cfg(feature = "ed25519")] pub fn into_ed25519(self) -> Option { #[allow(deprecated)] + #[allow(unreachable_patterns)] match self { PublicKey::Ed25519(inner) => Some(inner), _ => None, @@ -363,6 +368,7 @@ impl PublicKey { #[cfg(feature = "secp256k1")] pub fn into_secp256k1(self) -> Option { #[allow(deprecated)] + #[allow(unreachable_patterns)] match self { PublicKey::Secp256k1(inner) => Some(inner), _ => None, @@ -372,6 +378,7 @@ impl PublicKey { #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] pub fn into_rsa(self) -> Option { #[allow(deprecated)] + #[allow(unreachable_patterns)] match self { PublicKey::Rsa(inner) => Some(inner), _ => None, @@ -381,6 +388,7 @@ impl PublicKey { #[cfg(feature = "ecdsa")] pub fn into_ecdsa(self) -> Option { #[allow(deprecated)] + #[allow(unreachable_patterns)] match self { PublicKey::Ecdsa(inner) => Some(inner), _ => None, diff --git a/identity/src/peer_id.rs b/identity/src/peer_id.rs index ae9ffc80..1a96f431 100644 --- a/identity/src/peer_id.rs +++ b/identity/src/peer_id.rs @@ -19,11 +19,19 @@ // DEALINGS IN THE SOFTWARE. use multiaddr::{Multiaddr, Protocol}; -use multihash::{Code, Error, Multihash}; +use multihash::{Code, Error, MultihashGeneric}; use rand::Rng; +use sha2::Digest as _; use std::{convert::TryFrom, fmt, str::FromStr}; use thiserror::Error; +/// Local type-alias for multihash. +/// +/// Must be big enough to accommodate for `MAX_INLINE_KEY_LENGTH`. +/// 64 satisfies that and can hold 512 bit hashes which is what the ecosystem typically uses. +/// Given that this appears in our type-signature, using a "common" number here makes us more compatible. +type Multihash = MultihashGeneric<64>; + #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -31,6 +39,9 @@ use serde::{Deserialize, Serialize}; /// automatically used as the peer id using an identity multihash. const MAX_INLINE_KEY_LENGTH: usize = 42; +const MULTIHASH_IDENTITY_CODE: u64 = 0; +const MULTIHASH_SHA256_CODE: u64 = 0x12; + /// Identifier of a peer of the network. /// /// The data is a CIDv0 compatible multihash of the protobuf encoded public key of the peer @@ -55,18 +66,16 @@ impl fmt::Display for PeerId { impl PeerId { /// Builds a `PeerId` from a public key. pub fn from_public_key(key: &crate::keypair::PublicKey) -> PeerId { - use multihash::MultihashDigest as _; - let key_enc = key.to_protobuf_encoding(); - let hash_algorithm = if key_enc.len() <= MAX_INLINE_KEY_LENGTH { - Code::Identity + let multihash = if key_enc.len() <= MAX_INLINE_KEY_LENGTH { + Multihash::wrap(MULTIHASH_IDENTITY_CODE, &key_enc) + .expect("64 byte multihash provides sufficient space") } else { - Code::Sha2_256 + Multihash::wrap(MULTIHASH_SHA256_CODE, &sha2::Sha256::digest(key_enc)) + .expect("64 byte multihash provides sufficient space") }; - let multihash = hash_algorithm.digest(&key_enc); - PeerId { multihash } } @@ -82,9 +91,9 @@ impl PeerId { /// or the hash value does not satisfy the constraints for a hashed /// peer ID, it is returned as an `Err`. pub fn from_multihash(multihash: Multihash) -> Result { - match Code::try_from(multihash.code()) { - Ok(Code::Sha2_256) => Ok(PeerId { multihash }), - Ok(Code::Identity) if multihash.digest().len() <= MAX_INLINE_KEY_LENGTH => { + match multihash.code() { + MULTIHASH_SHA256_CODE => Ok(PeerId { multihash }), + MULTIHASH_IDENTITY_CODE if multihash.digest().len() <= MAX_INLINE_KEY_LENGTH => { Ok(PeerId { multihash }) } _ => Err(multihash), diff --git a/protocols/kad/src/behaviour/test.rs b/protocols/kad/src/behaviour/test.rs index f848812d..33e48377 100644 --- a/protocols/kad/src/behaviour/test.rs +++ b/protocols/kad/src/behaviour/test.rs @@ -24,13 +24,13 @@ use super::*; use crate::kbucket::Distance; use crate::record::{store::MemoryStore, Key}; -use crate::K_VALUE; +use crate::{K_VALUE, SHA_256_MH}; use futures::{executor::block_on, future::poll_fn, prelude::*}; use futures_timer::Delay; use libp2p_core::{ connection::ConnectedPoint, multiaddr::{multiaddr, Multiaddr, Protocol}, - multihash::{Code, Multihash, MultihashDigest}, + multihash::Multihash, transport::MemoryTransport, upgrade, Endpoint, Transport, }; @@ -138,7 +138,7 @@ fn build_fully_connected_nodes_with_config( } fn random_multihash() -> Multihash { - Multihash::wrap(Code::Sha2_256.into(), &thread_rng().gen::<[u8; 32]>()).unwrap() + Multihash::wrap(SHA_256_MH, &thread_rng().gen::<[u8; 32]>()).unwrap() } #[derive(Clone, Debug)] @@ -1100,7 +1100,10 @@ fn disjoint_query_does_not_finish_before_all_paths_did() { let mut trudy = build_node(); // Trudy the intrudor, an adversary. let mut bob = build_node(); - let key = Key::from(Code::Sha2_256.digest(&thread_rng().gen::<[u8; 32]>())); + let key = Key::from( + Multihash::wrap(SHA_256_MH, &thread_rng().gen::<[u8; 32]>()) + .expect("32 array to fit into 64 byte multihash"), + ); let record_bob = Record::new(key.clone(), b"bob".to_vec()); let record_trudy = Record::new(key.clone(), b"trudy".to_vec()); diff --git a/protocols/kad/src/kbucket/key.rs b/protocols/kad/src/kbucket/key.rs index c2ea38a1..af2999eb 100644 --- a/protocols/kad/src/kbucket/key.rs +++ b/protocols/kad/src/kbucket/key.rs @@ -196,7 +196,7 @@ impl Distance { #[cfg(test)] mod tests { use super::*; - use libp2p_core::multihash::Code; + use crate::SHA_256_MH; use quickcheck::*; impl Arbitrary for Key { @@ -208,7 +208,7 @@ mod tests { impl Arbitrary for Key { fn arbitrary(g: &mut Gen) -> Key { let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g)); - Key::from(Multihash::wrap(Code::Sha2_256.into(), &hash).unwrap()) + Key::from(Multihash::wrap(SHA_256_MH, &hash).unwrap()) } } diff --git a/protocols/kad/src/lib.rs b/protocols/kad/src/lib.rs index 3e9dcecc..979aedc9 100644 --- a/protocols/kad/src/lib.rs +++ b/protocols/kad/src/lib.rs @@ -100,3 +100,7 @@ pub const K_VALUE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(20) }; /// /// The current value is `3`. pub const ALPHA_VALUE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(3) }; + +/// Constant shared across tests for the [`Multihash`](libp2p_core::multihash::Multihash) type. +#[cfg(test)] +const SHA_256_MH: u64 = 0x12; diff --git a/protocols/kad/src/query/peers/closest.rs b/protocols/kad/src/query/peers/closest.rs index 0f84ee5f..a6611c1b 100644 --- a/protocols/kad/src/query/peers/closest.rs +++ b/protocols/kad/src/query/peers/closest.rs @@ -475,7 +475,8 @@ enum PeerState { #[cfg(test)] mod tests { use super::*; - use libp2p_core::multihash::{Code, Multihash}; + use crate::SHA_256_MH; + use libp2p_core::multihash::Multihash; use libp2p_identity::PeerId; use quickcheck::*; use rand::{rngs::StdRng, Rng, SeedableRng}; @@ -484,10 +485,8 @@ mod tests { fn random_peers(n: usize, g: &mut R) -> Vec { (0..n) .map(|_| { - PeerId::from_multihash( - Multihash::wrap(Code::Sha2_256.into(), &g.gen::<[u8; 32]>()).unwrap(), - ) - .unwrap() + PeerId::from_multihash(Multihash::wrap(SHA_256_MH, &g.gen::<[u8; 32]>()).unwrap()) + .unwrap() }) .collect() } @@ -505,8 +504,7 @@ mod tests { fn arbitrary(g: &mut Gen) -> ArbitraryPeerId { let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g)); let peer_id = - PeerId::from_multihash(Multihash::wrap(Code::Sha2_256.into(), &hash).unwrap()) - .unwrap(); + PeerId::from_multihash(Multihash::wrap(SHA_256_MH, &hash).unwrap()).unwrap(); ArbitraryPeerId(peer_id) } } diff --git a/protocols/kad/src/query/peers/closest/disjoint.rs b/protocols/kad/src/query/peers/closest/disjoint.rs index cbee599f..61c92257 100644 --- a/protocols/kad/src/query/peers/closest/disjoint.rs +++ b/protocols/kad/src/query/peers/closest/disjoint.rs @@ -444,8 +444,8 @@ impl>> Iterator for ResultIter { mod tests { use super::*; - use crate::K_VALUE; - use libp2p_core::multihash::{Code, Multihash}; + use crate::{K_VALUE, SHA_256_MH}; + use libp2p_core::multihash::Multihash; use quickcheck::*; use std::collections::HashSet; use std::iter; @@ -531,8 +531,7 @@ mod tests { fn arbitrary(g: &mut Gen) -> ArbitraryPeerId { let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g)); let peer_id = - PeerId::from_multihash(Multihash::wrap(Code::Sha2_256.into(), &hash).unwrap()) - .unwrap(); + PeerId::from_multihash(Multihash::wrap(SHA_256_MH, &hash).unwrap()).unwrap(); ArbitraryPeerId(peer_id) } } diff --git a/protocols/kad/src/record.rs b/protocols/kad/src/record.rs index 814d7fa1..2abe32d5 100644 --- a/protocols/kad/src/record.rs +++ b/protocols/kad/src/record.rs @@ -161,14 +161,14 @@ impl ProviderRecord { #[cfg(test)] mod tests { use super::*; - use libp2p_core::multihash::Code; + use crate::SHA_256_MH; use quickcheck::*; use std::time::Duration; impl Arbitrary for Key { fn arbitrary(g: &mut Gen) -> Key { let hash: [u8; 32] = core::array::from_fn(|_| u8::arbitrary(g)); - Key::from(Multihash::wrap(Code::Sha2_256.into(), &hash).unwrap()) + Key::from(Multihash::wrap(SHA_256_MH, &hash).unwrap()) } } diff --git a/protocols/kad/src/record/store/memory.rs b/protocols/kad/src/record/store/memory.rs index fdc63160..1d4caab3 100644 --- a/protocols/kad/src/record/store/memory.rs +++ b/protocols/kad/src/record/store/memory.rs @@ -216,12 +216,13 @@ impl RecordStore for MemoryStore { #[cfg(test)] mod tests { use super::*; - use libp2p_core::multihash::{Code, Multihash}; + use crate::SHA_256_MH; + use libp2p_core::multihash::Multihash; use quickcheck::*; use rand::Rng; fn random_multihash() -> Multihash { - Multihash::wrap(Code::Sha2_256.into(), &rand::thread_rng().gen::<[u8; 32]>()).unwrap() + Multihash::wrap(SHA_256_MH, &rand::thread_rng().gen::<[u8; 32]>()).unwrap() } fn distance(r: &ProviderRecord) -> kbucket::Distance { diff --git a/transports/webrtc/Cargo.toml b/transports/webrtc/Cargo.toml index 6f18265c..cf4c5802 100644 --- a/transports/webrtc/Cargo.toml +++ b/transports/webrtc/Cargo.toml @@ -22,7 +22,8 @@ libp2p-core = { version = "0.39.0", path = "../../core" } libp2p-noise = { version = "0.42.0", path = "../../transports/noise" } libp2p-identity = { version = "0.1.0", path = "../../identity" } log = "0.4" -multihash = { version = "0.17.0", default-features = false, features = ["sha2"] } +sha2 = "0.10.6" +multihash = { version = "0.17.0", default-features = false } quick-protobuf = "0.8" quick-protobuf-codec = { version = "0.1", path = "../../misc/quick-protobuf-codec" } rand = "0.8" diff --git a/transports/webrtc/src/tokio/fingerprint.rs b/transports/webrtc/src/tokio/fingerprint.rs index 8a03044c..3776f0dc 100644 --- a/transports/webrtc/src/tokio/fingerprint.rs +++ b/transports/webrtc/src/tokio/fingerprint.rs @@ -18,12 +18,15 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use multihash::{Code, Hasher, Multihash, MultihashDigest}; +use multihash::MultihashGeneric; +use sha2::Digest as _; +use std::fmt; use webrtc::dtls_transport::dtls_fingerprint::RTCDtlsFingerprint; -use std::fmt; - const SHA256: &str = "sha-256"; +const MULTIHASH_SHA256_CODE: u64 = 0x12; + +type Multihash = MultihashGeneric<64>; /// A certificate fingerprint that is assumed to be created using the SHA256 hash algorithm. #[derive(Eq, PartialEq, Copy, Clone)] @@ -39,13 +42,7 @@ impl Fingerprint { /// Creates a fingerprint from a raw certificate. pub fn from_certificate(bytes: &[u8]) -> Self { - let mut h = multihash::Sha2_256::default(); - h.update(bytes); - - let mut bytes: [u8; 32] = [0; 32]; - bytes.copy_from_slice(h.finalize()); - - Fingerprint(bytes) + Fingerprint(sha2::Sha256::digest(bytes).into()) } /// Converts [`RTCDtlsFingerprint`] to [`Fingerprint`]. @@ -60,9 +57,9 @@ impl Fingerprint { Some(Self(buf)) } - /// Converts [`type@Multihash`] to [`Fingerprint`]. + /// Converts [`Multihash`](MultihashGeneric) to [`Fingerprint`]. pub fn try_from_multihash(hash: Multihash) -> Option { - if hash.code() != u64::from(Code::Sha2_256) { + if hash.code() != MULTIHASH_SHA256_CODE { // Only support SHA256 for now. return None; } @@ -72,11 +69,9 @@ impl Fingerprint { Some(Self(bytes)) } - /// Converts this fingerprint to [`type@Multihash`]. + /// Converts this fingerprint to [`Multihash`](MultihashGeneric). pub fn to_multihash(self) -> Multihash { - Code::Sha2_256 - .wrap(&self.0) - .expect("fingerprint's len to be 32 bytes") + Multihash::wrap(MULTIHASH_SHA256_CODE, &self.0).expect("fingerprint's len to be 32 bytes") } /// Formats this fingerprint as uppercase hex, separated by colons (`:`).