diff --git a/Cargo.toml b/Cargo.toml index a1fef2476bf6..4f36c634c049 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ secp256k1 = ["libp2p-core/secp256k1", "libp2p-secio/secp256k1"] bytes = "0.5" futures = "0.3.1" multiaddr = { package = "parity-multiaddr", version = "0.7.2", path = "misc/multiaddr" } -multihash = { package = "parity-multihash", version = "0.2.1", path = "misc/multihash" } +multihash = "0.10" lazy_static = "1.2" libp2p-mplex = { version = "0.16.0", path = "muxers/mplex" } libp2p-identify = { version = "0.16.0", path = "protocols/identify" } @@ -56,7 +56,6 @@ members = [ "core", "misc/core-derive", "misc/multiaddr", - "misc/multihash", "misc/multistream-select", "misc/peer-id-generator", "muxers/mplex", diff --git a/core/Cargo.toml b/core/Cargo.toml index 0ef54957d0ba..98680d504dac 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -20,7 +20,7 @@ lazy_static = "1.2" libsecp256k1 = { version = "0.3.1", optional = true } log = "0.4" multiaddr = { package = "parity-multiaddr", version = "0.7.2", path = "../misc/multiaddr" } -multihash = { package = "parity-multihash", version = "0.2.1", path = "../misc/multihash" } +multihash = "0.10" multistream-select = { version = "0.7.0", path = "../misc/multistream-select" } parking_lot = "0.10.0" pin-project = "0.4.6" diff --git a/core/src/peer_id.rs b/core/src/peer_id.rs index 09a8d7cdaed4..3ac0ecad9cb8 100644 --- a/core/src/peer_id.rs +++ b/core/src/peer_id.rs @@ -21,8 +21,9 @@ use crate::PublicKey; use bs58; use thiserror::Error; -use multihash; +use multihash::{self, Code, Sha2_256}; use std::{convert::TryFrom, borrow::Borrow, fmt, hash, str::FromStr}; +use rand::RngCore; /// Public keys with byte-lengths smaller than `MAX_INLINE_KEY_LENGTH` will be /// automatically used as the peer id using an identity multihash. @@ -69,17 +70,16 @@ impl PeerId { // will switch to not hashing the key (i.e. the correct behaviour). // In other words, rust-libp2p 0.16 is compatible with all versions of rust-libp2p. // Rust-libp2p 0.12 and below is **NOT** compatible with rust-libp2p 0.17 and above. - let (hash_algorithm, canonical_algorithm) = /*if key_enc.len() <= MAX_INLINE_KEY_LENGTH { + let (hash_algorithm, canonical_algorithm): (_, Option) = /*if key_enc.len() <= MAX_INLINE_KEY_LENGTH { (multihash::Hash::Identity, Some(multihash::Hash::SHA2256)) } else {*/ - (multihash::Hash::SHA2256, None); + (Code::Sha2_256, None); //}; let canonical = canonical_algorithm.map(|alg| - multihash::encode(alg, &key_enc).expect("SHA2256 is always supported")); + alg.hasher().expect("canonical hasher exists").digest(&key_enc)); - let multihash = multihash::encode(hash_algorithm, &key_enc) - .expect("identity and sha2-256 are always supported by known public key types"); + let multihash = hash_algorithm.hasher().expect("hasher exists").digest(&key_enc); PeerId { multihash, canonical } } @@ -89,12 +89,11 @@ impl PeerId { pub fn from_bytes(data: Vec) -> Result> { match multihash::Multihash::from_bytes(data) { Ok(multihash) => { - if multihash.algorithm() == multihash::Hash::SHA2256 { + if multihash.algorithm() == multihash::Code::Sha2_256 { Ok(PeerId { multihash, canonical: None }) } - else if multihash.algorithm() == multihash::Hash::Identity { - let canonical = multihash::encode(multihash::Hash::SHA2256, multihash.digest()) - .expect("SHA2256 is always supported"); + else if multihash.algorithm() == multihash::Code::Identity { + let canonical = Sha2_256::digest(&multihash.digest()); Ok(PeerId { multihash, canonical: Some(canonical) }) } else { Err(multihash.into_bytes()) @@ -107,11 +106,10 @@ impl PeerId { /// Turns a `Multihash` into a `PeerId`. If the multihash doesn't use the correct algorithm, /// returns back the data as an error. pub fn from_multihash(data: multihash::Multihash) -> Result { - if data.algorithm() == multihash::Hash::SHA2256 { + if data.algorithm() == multihash::Code::Sha2_256 { Ok(PeerId { multihash: data, canonical: None }) - } else if data.algorithm() == multihash::Hash::Identity { - let canonical = multihash::encode(multihash::Hash::SHA2256, data.digest()) - .expect("SHA2256 is always supported"); + } else if data.algorithm() == multihash::Code::Identity { + let canonical = Sha2_256::digest(data.digest()); Ok(PeerId { multihash: data, canonical: Some(canonical) }) } else { Err(data) @@ -122,8 +120,10 @@ impl PeerId { /// /// This is useful for randomly walking on a DHT, or for testing purposes. pub fn random() -> PeerId { + let mut peer_id = Vec::with_capacity(32); + rand::thread_rng().fill_bytes(&mut peer_id[..]); PeerId { - multihash: multihash::Multihash::random(multihash::Hash::SHA2256), + multihash: multihash::wrap(multihash::Code::Sha2_256, &peer_id), canonical: None, } } @@ -158,11 +158,7 @@ impl PeerId { pub fn is_public_key(&self, public_key: &PublicKey) -> Option { let alg = self.multihash.algorithm(); let enc = public_key.clone().into_protobuf_encoding(); - match multihash::encode(alg, &enc) { - Ok(h) => Some(h == self.multihash), - Err(multihash::EncodeError::UnsupportedType) => None, - Err(multihash::EncodeError::UnsupportedInputLength) => None, - } + Some(alg.hasher()?.digest(&enc) == self.multihash) } } @@ -283,8 +279,8 @@ mod tests { #[test] fn peer_id_identity_equal_to_sha2256() { let random_bytes = (0..64).map(|_| rand::random::()).collect::>(); - let mh1 = multihash::encode(multihash::Hash::SHA2256, &random_bytes).unwrap(); - let mh2 = multihash::encode(multihash::Hash::Identity, &random_bytes).unwrap(); + let mh1 = multihash::Sha2_256::digest(&random_bytes); + let mh2 = multihash::Identity::digest(&random_bytes); let peer_id1 = PeerId::try_from(mh1).unwrap(); let peer_id2 = PeerId::try_from(mh2).unwrap(); assert_eq!(peer_id1, peer_id2); @@ -294,8 +290,8 @@ mod tests { #[test] fn peer_id_identity_hashes_equal_to_sha2256() { let random_bytes = (0..64).map(|_| rand::random::()).collect::>(); - let mh1 = multihash::encode(multihash::Hash::SHA2256, &random_bytes).unwrap(); - let mh2 = multihash::encode(multihash::Hash::Identity, &random_bytes).unwrap(); + let mh1 = multihash::Sha2_256::digest(&random_bytes); + let mh2 = multihash::Identity::digest(&random_bytes); let peer_id1 = PeerId::try_from(mh1).unwrap(); let peer_id2 = PeerId::try_from(mh2).unwrap(); @@ -309,26 +305,26 @@ mod tests { #[test] fn peer_id_equal_across_algorithms() { - use multihash::Hash; + use multihash::Code; use quickcheck::{Arbitrary, Gen}; #[derive(Debug, Clone, PartialEq, Eq)] - struct HashAlgo(Hash); + struct HashAlgo(Code); impl Arbitrary for HashAlgo { fn arbitrary(g: &mut G) -> Self { match g.next_u32() % 4 { // make Hash::Identity more likely - 0 => HashAlgo(Hash::SHA2256), - _ => HashAlgo(Hash::Identity) + 0 => HashAlgo(Code::Sha2_256), + _ => HashAlgo(Code::Identity) } } } fn property(data: Vec, algo1: HashAlgo, algo2: HashAlgo) -> bool { - let a = PeerId::try_from(multihash::encode(algo1.0, &data).unwrap()).unwrap(); - let b = PeerId::try_from(multihash::encode(algo2.0, &data).unwrap()).unwrap(); + let a = PeerId::try_from(algo1.0.hasher().unwrap().digest(&data)).unwrap(); + let b = PeerId::try_from(algo2.0.hasher().unwrap().digest(&data)).unwrap(); - if algo1 == algo2 || algo1.0 == Hash::Identity || algo2.0 == Hash::Identity { + if algo1 == algo2 || algo1.0 == Code::Identity || algo2.0 == Code::Identity { a == b } else { a != b diff --git a/misc/multiaddr/Cargo.toml b/misc/multiaddr/Cargo.toml index cdcd5ba29d87..6860c5da4855 100644 --- a/misc/multiaddr/Cargo.toml +++ b/misc/multiaddr/Cargo.toml @@ -13,7 +13,7 @@ arrayref = "0.3" bs58 = "0.3.0" byteorder = "1.3.1" data-encoding = "2.1" -multihash = { package = "parity-multihash", version = "0.2.1", path = "../multihash" } +multihash = "0.10" percent-encoding = "2.1.0" serde = "1.0.70" static_assertions = "1.1" diff --git a/misc/multihash/.gitignore b/misc/multihash/.gitignore deleted file mode 100644 index 89ece56c0b94..000000000000 --- a/misc/multihash/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -target -Cargo.lock -*.bk \ No newline at end of file diff --git a/misc/multihash/.travis.yml b/misc/multihash/.travis.yml deleted file mode 100644 index 71152f691720..000000000000 --- a/misc/multihash/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -sudo: false - -language: rust - -addons: - apt: - packages: - - libcurl4-openssl-dev - - libelf-dev - - libdw-dev - - binutils-dev - -rust: - - beta - - stable - -before_script: - - | - pip install 'travis-cargo<0.2' --user && - export PATH=$HOME/.local/bin:$PATH - -install: - - pip install --user travis-cargo codecov - - export PATH=$PATH:$HOME/.local/bin - -script: - - | - travis-cargo build && - travis-cargo test && - travis-cargo --only stable doc - -after_success: - - travis-cargo coverage --no-sudo - - codecov --file target/kcov/kcov-merged/cobertura.xml diff --git a/misc/multihash/Cargo.toml b/misc/multihash/Cargo.toml deleted file mode 100644 index 5b5980b765d9..000000000000 --- a/misc/multihash/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "parity-multihash" -edition = "2018" -description = "Implementation of the multihash format" -repository = "https://github.com/libp2p/rust-libp2p" -keywords = ["multihash", "ipfs"] -version = "0.2.3" -authors = ["dignifiedquire ", "Parity Technologies "] -license = "MIT" -documentation = "https://docs.rs/parity-multihash/" - -[dependencies] -blake2 = { version = "0.8", default-features = false } -bytes = "0.5" -rand = { version = "0.7", default-features = false, features = ["std"] } -sha-1 = { version = "0.8", default-features = false } -sha2 = { version = "0.8", default-features = false } -sha3 = { version = "0.8", default-features = false } -unsigned-varint = "0.3" diff --git a/misc/multihash/LICENSE b/misc/multihash/LICENSE deleted file mode 100644 index 233fd7bd7d5a..000000000000 --- a/misc/multihash/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License - -Copyright (C) 2015-2016 Friedel Ziegelmayer - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Status API Training Shop Blog About Pricing diff --git a/misc/multihash/src/errors.rs b/misc/multihash/src/errors.rs deleted file mode 100644 index df3ba85377f6..000000000000 --- a/misc/multihash/src/errors.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::{error, fmt}; - -/// Error that can happen when encoding some bytes into a multihash. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum EncodeError { - /// The requested hash algorithm isn't supported by this library. - UnsupportedType, - /// The input length is too large for the hash algorithm. - UnsupportedInputLength, -} - -impl fmt::Display for EncodeError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - EncodeError::UnsupportedType => write!(f, "This type is not supported yet"), - EncodeError::UnsupportedInputLength => write!( - f, - "The length of the input for the given hash is not yet supported" - ), - } - } -} - -impl error::Error for EncodeError {} - -/// Error that can happen when decoding some bytes. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum DecodeError { - /// The input doesn't have a correct length. - BadInputLength, - /// The code of the hashing algorithm is incorrect. - UnknownCode, -} - -impl fmt::Display for DecodeError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - DecodeError::BadInputLength => write!(f, "Not matching input length"), - DecodeError::UnknownCode => write!(f, "Found unknown code"), - } - } -} - -impl error::Error for DecodeError {} - -/// Error that can happen when decoding some bytes. -/// -/// Same as `DecodeError`, but allows retreiving the data whose decoding was attempted. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct DecodeOwnedError { - /// The error. - pub error: DecodeError, - /// The data whose decoding was attempted. - pub data: Vec, -} - -impl fmt::Display for DecodeOwnedError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.error) - } -} - -impl error::Error for DecodeOwnedError {} diff --git a/misc/multihash/src/hashes.rs b/misc/multihash/src/hashes.rs deleted file mode 100644 index bd7c431e248e..000000000000 --- a/misc/multihash/src/hashes.rs +++ /dev/null @@ -1,107 +0,0 @@ -/// List of types currently supported in the multihash spec. -/// -/// Not all hash types are supported by this library. -#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)] -pub enum Hash { - /// Identity (Raw binary ) - Identity, - /// SHA-1 (20-byte hash size) - SHA1, - /// SHA-256 (32-byte hash size) - SHA2256, - /// SHA-512 (64-byte hash size) - SHA2512, - /// SHA3-512 (64-byte hash size) - SHA3512, - /// SHA3-384 (48-byte hash size) - SHA3384, - /// SHA3-256 (32-byte hash size) - SHA3256, - /// SHA3-224 (28-byte hash size) - SHA3224, - /// Keccak-224 (28-byte hash size) - Keccak224, - /// Keccak-256 (32-byte hash size) - Keccak256, - /// Keccak-384 (48-byte hash size) - Keccak384, - /// Keccak-512 (64-byte hash size) - Keccak512, - /// BLAKE2b-512 (64-byte hash size) - Blake2b512, - /// BLAKE2b-256 (32-byte hash size) - Blake2b256, - /// BLAKE2s-256 (32-byte hash size) - Blake2s256, - /// BLAKE2s-128 (16-byte hash size) - Blake2s128, -} - -impl Hash { - /// Get the corresponding hash code. - pub fn code(&self) -> u16 { - match self { - Hash::Identity => 0x00, - Hash::SHA1 => 0x11, - Hash::SHA2256 => 0x12, - Hash::SHA2512 => 0x13, - Hash::SHA3224 => 0x17, - Hash::SHA3256 => 0x16, - Hash::SHA3384 => 0x15, - Hash::SHA3512 => 0x14, - Hash::Keccak224 => 0x1A, - Hash::Keccak256 => 0x1B, - Hash::Keccak384 => 0x1C, - Hash::Keccak512 => 0x1D, - Hash::Blake2b512 => 0xB240, - Hash::Blake2b256 => 0xB220, - Hash::Blake2s256 => 0xB260, - Hash::Blake2s128 => 0xB250, - } - } - - /// Get the hash length in bytes. - pub fn size(&self) -> u8 { - match self { - Hash::Identity => 42, - Hash::SHA1 => 20, - Hash::SHA2256 => 32, - Hash::SHA2512 => 64, - Hash::SHA3224 => 28, - Hash::SHA3256 => 32, - Hash::SHA3384 => 48, - Hash::SHA3512 => 64, - Hash::Keccak224 => 28, - Hash::Keccak256 => 32, - Hash::Keccak384 => 48, - Hash::Keccak512 => 64, - Hash::Blake2b512 => 64, - Hash::Blake2b256 => 32, - Hash::Blake2s256 => 32, - Hash::Blake2s128 => 16, - } - } - - /// Returns the algorithm corresponding to a code, or `None` if no algorithm is matching. - pub fn from_code(code: u16) -> Option { - Some(match code { - 0x00 => Hash::Identity, - 0x11 => Hash::SHA1, - 0x12 => Hash::SHA2256, - 0x13 => Hash::SHA2512, - 0x14 => Hash::SHA3512, - 0x15 => Hash::SHA3384, - 0x16 => Hash::SHA3256, - 0x17 => Hash::SHA3224, - 0x1A => Hash::Keccak224, - 0x1B => Hash::Keccak256, - 0x1C => Hash::Keccak384, - 0x1D => Hash::Keccak512, - 0xB240 => Hash::Blake2b512, - 0xB220 => Hash::Blake2b256, - 0xB260 => Hash::Blake2s256, - 0xB250 => Hash::Blake2s128, - _ => return None, - }) - } -} diff --git a/misc/multihash/src/lib.rs b/misc/multihash/src/lib.rs deleted file mode 100644 index fe5d2f529014..000000000000 --- a/misc/multihash/src/lib.rs +++ /dev/null @@ -1,382 +0,0 @@ -//! # Multihash -//! -//! Implementation of [multihash](https://github.com/multiformats/multihash) in Rust. -//! -//! A `Multihash` is a structure that contains a hashing algorithm, plus some hashed data. -//! A `MultihashRef` is the same as a `Multihash`, except that it doesn't own its data. - -mod errors; -mod hashes; - -use std::{convert::TryFrom, fmt::Write}; - -use bytes::{BufMut, Bytes, BytesMut}; -use rand::RngCore; -use sha2::digest::{self, VariableOutput}; -use std::borrow::Borrow; -use unsigned_varint::{decode, encode}; - -pub use self::errors::{DecodeError, DecodeOwnedError, EncodeError}; -pub use self::hashes::Hash; - -/// Helper function for encoding input into output using given `Digest` -fn digest_encode(input: &[u8], output: &mut [u8]) { - output.copy_from_slice(&D::digest(input)) -} - -// And another one to keep the matching DRY -macro_rules! match_encoder { - ($hash_id:ident for ($input:expr, $output:expr) { - $( $hashtype:ident => $hash_ty:path, )* - }) => ({ - match $hash_id { - $( - Hash::$hashtype => digest_encode::<$hash_ty>($input, $output), - )* - - _ => return Err(EncodeError::UnsupportedType) - } - }) -} - -/// Encodes data into a multihash. -/// -/// # Errors -/// -/// Will return an error if the specified hash type is not supported. See the docs for `Hash` -/// to see what is supported. -/// -/// # Examples -/// -/// ``` -/// use parity_multihash::{encode, Hash}; -/// -/// assert_eq!( -/// encode(Hash::SHA2256, b"hello world").unwrap().to_vec(), -/// vec![18, 32, 185, 77, 39, 185, 147, 77, 62, 8, 165, 46, 82, 215, 218, 125, 171, 250, 196, -/// 132, 239, 227, 122, 83, 128, 238, 144, 136, 247, 172, 226, 239, 205, 233] -/// ); -/// ``` -/// -pub fn encode(hash: Hash, input: &[u8]) -> Result { - // Custom length encoding for the identity multihash - if let Hash::Identity = hash { - if u64::from(std::u32::MAX) < as_u64(input.len()) { - return Err(EncodeError::UnsupportedInputLength); - } - let mut buf = encode::u16_buffer(); - let code = encode::u16(hash.code(), &mut buf); - let mut len_buf = encode::u32_buffer(); - let size = encode::u32(input.len() as u32, &mut len_buf); - - let total_len = code.len() + size.len() + input.len(); - - let mut output = BytesMut::with_capacity(total_len); - output.put_slice(code); - output.put_slice(size); - output.put_slice(input); - Ok(Multihash { - bytes: output.freeze(), - }) - } else { - let (offset, mut output) = encode_hash(hash); - match_encoder!(hash for (input, &mut output[offset ..]) { - SHA1 => sha1::Sha1, - SHA2256 => sha2::Sha256, - SHA2512 => sha2::Sha512, - SHA3224 => sha3::Sha3_224, - SHA3256 => sha3::Sha3_256, - SHA3384 => sha3::Sha3_384, - SHA3512 => sha3::Sha3_512, - Keccak224 => sha3::Keccak224, - Keccak256 => sha3::Keccak256, - Keccak384 => sha3::Keccak384, - Keccak512 => sha3::Keccak512, - Blake2b512 => blake2::Blake2b, - Blake2b256 => Blake2b256, - Blake2s256 => blake2::Blake2s, - Blake2s128 => Blake2s128, - }); - Ok(Multihash { - bytes: output.freeze(), - }) - } -} - -// Encode the given [`Hash`] value and ensure the returned [`BytesMut`] -// has enough capacity to hold the actual digest. -fn encode_hash(hash: Hash) -> (usize, BytesMut) { - let mut buf = encode::u16_buffer(); - let code = encode::u16(hash.code(), &mut buf); - - let len = code.len() + 1 + usize::from(hash.size()); - - let mut output = BytesMut::with_capacity(len); - output.put_slice(code); - output.put_u8(hash.size()); - output.resize(len, 0); - - (code.len() + 1, output) -} - -/// BLAKE2b-256 (32-byte hash size) -#[derive(Debug, Clone)] -struct Blake2b256(blake2::VarBlake2b); - -impl Default for Blake2b256 { - fn default() -> Self { - Blake2b256(blake2::VarBlake2b::new(32).unwrap()) - } -} - -impl digest::Input for Blake2b256 { - fn input>(&mut self, data: B) { - self.0.input(data) - } -} - -impl digest::FixedOutput for Blake2b256 { - type OutputSize = digest::generic_array::typenum::U32; - - fn fixed_result(self) -> digest::generic_array::GenericArray { - let mut out = digest::generic_array::GenericArray::default(); - self.0.variable_result(|slice| { - assert_eq!(slice.len(), 32); - out.copy_from_slice(slice) - }); - out - } -} - -impl digest::Reset for Blake2b256 { - fn reset(&mut self) { - self.0.reset() - } -} - -/// BLAKE2s-128 (16-byte hash size) -#[derive(Debug, Clone)] -struct Blake2s128(blake2::VarBlake2s); - -impl Default for Blake2s128 { - fn default() -> Self { - Blake2s128(blake2::VarBlake2s::new(16).unwrap()) - } -} - -impl digest::Input for Blake2s128 { - fn input>(&mut self, data: B) { - self.0.input(data) - } -} - -impl digest::FixedOutput for Blake2s128 { - type OutputSize = digest::generic_array::typenum::U16; - - fn fixed_result(self) -> digest::generic_array::GenericArray { - let mut out = digest::generic_array::GenericArray::default(); - self.0.variable_result(|slice| { - assert_eq!(slice.len(), 16); - out.copy_from_slice(slice) - }); - out - } -} - -impl digest::Reset for Blake2s128 { - fn reset(&mut self) { - self.0.reset() - } -} - -/// Represents a valid multihash. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Multihash { bytes: Bytes } - -impl Multihash { - /// Verifies whether `bytes` contains a valid multihash, and if so returns a `Multihash`. - pub fn from_bytes(bytes: Vec) -> Result { - if let Err(err) = MultihashRef::from_slice(&bytes) { - return Err(DecodeOwnedError { error: err, data: bytes }); - } - Ok(Multihash { bytes: Bytes::from(bytes) }) - } - - /// Generates a random `Multihash` from a cryptographically secure PRNG. - pub fn random(hash: Hash) -> Multihash { - let (offset, mut bytes) = encode_hash(hash); - rand::thread_rng().fill_bytes(&mut bytes[offset ..]); - Multihash { bytes: bytes.freeze() } - } - - /// Returns the bytes representation of the multihash. - pub fn into_bytes(self) -> Vec { - self.to_vec() - } - - /// Returns the bytes representation of the multihash. - pub fn to_vec(&self) -> Vec { - Vec::from(&self.bytes[..]) - } - - /// Returns the bytes representation of this multihash. - pub fn as_bytes(&self) -> &[u8] { - &self.bytes - } - - /// Builds a `MultihashRef` corresponding to this `Multihash`. - pub fn as_ref(&self) -> MultihashRef<'_> { - MultihashRef { bytes: &self.bytes } - } - - /// Returns which hashing algorithm is used in this multihash. - pub fn algorithm(&self) -> Hash { - self.as_ref().algorithm() - } - - /// Returns the hashed data. - pub fn digest(&self) -> &[u8] { - self.as_ref().digest() - } -} - -impl AsRef<[u8]> for Multihash { - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } -} - -impl Borrow<[u8]> for Multihash { - fn borrow(&self) -> &[u8] { - self.as_bytes() - } -} - -impl<'a> PartialEq> for Multihash { - fn eq(&self, other: &MultihashRef<'a>) -> bool { - &*self.bytes == other.bytes - } -} - -impl TryFrom> for Multihash { - type Error = DecodeOwnedError; - - fn try_from(value: Vec) -> Result { - Multihash::from_bytes(value) - } -} - -/// Represents a valid multihash. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct MultihashRef<'a> { bytes: &'a [u8] } - -impl<'a> MultihashRef<'a> { - /// Creates a `MultihashRef` from the given `input`. - pub fn from_slice(input: &'a [u8]) -> Result { - if input.is_empty() { - return Err(DecodeError::BadInputLength); - } - - // Ensure `Hash::code` returns a `u16` so that our `decode::u16` here is correct. - std::convert::identity:: u16>(Hash::code); - let (code, bytes) = decode::u16(&input).map_err(|_| DecodeError::BadInputLength)?; - - let alg = Hash::from_code(code).ok_or(DecodeError::UnknownCode)?; - - // handle the identity case - if alg == Hash::Identity { - let (hash_len, bytes) = decode::u32(&bytes).map_err(|_| DecodeError::BadInputLength)?; - if as_u64(bytes.len()) != u64::from(hash_len) { - return Err(DecodeError::BadInputLength); - } - return Ok(MultihashRef { bytes: input }); - } - - let hash_len = usize::from(alg.size()); - - // Length of input after hash code should be exactly hash_len + 1 - if bytes.len() != hash_len + 1 { - return Err(DecodeError::BadInputLength); - } - - if usize::from(bytes[0]) != hash_len { - return Err(DecodeError::BadInputLength); - } - - Ok(MultihashRef { bytes: input }) - } - - /// Returns which hashing algorithm is used in this multihash. - pub fn algorithm(&self) -> Hash { - let code = decode::u16(&self.bytes) - .expect("multihash is known to be valid algorithm") - .0; - Hash::from_code(code).expect("multihash is known to be valid") - } - - /// Returns the hashed data. - pub fn digest(&self) -> &'a [u8] { - let bytes = decode::u16(&self.bytes) - .expect("multihash is known to be valid digest") - .1; - &bytes[1 ..] - } - - /// Builds a `Multihash` that owns the data. - /// - /// This operation allocates. - pub fn into_owned(self) -> Multihash { - Multihash { - bytes: Bytes::copy_from_slice(self.bytes) - } - } - - /// Returns the bytes representation of this multihash. - pub fn as_bytes(&self) -> &'a [u8] { - &self.bytes - } -} - -impl<'a> PartialEq for MultihashRef<'a> { - fn eq(&self, other: &Multihash) -> bool { - self.bytes == &*other.bytes - } -} - -#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] -fn as_u64(a: usize) -> u64 { - a as u64 -} - -/// Convert bytes to a hex representation -pub fn to_hex(bytes: &[u8]) -> String { - let mut hex = String::with_capacity(bytes.len() * 2); - - for byte in bytes { - write!(hex, "{:02x}", byte).expect("Can't fail on writing to string"); - } - - hex -} - -#[cfg(test)] -mod tests { - use crate::{Hash, Multihash}; - use std::convert::TryFrom; - - #[test] - fn rand_generates_valid_multihash() { - // Iterate over every possible hash function. - for code in 0 .. u16::max_value() { - let hash_fn = match Hash::from_code(code) { - Some(c) => c, - None => continue, - }; - - for _ in 0 .. 2000 { - let hash = Multihash::random(hash_fn); - assert_eq!(hash, Multihash::try_from(hash.to_vec()).unwrap()); - } - } - } -} diff --git a/misc/multihash/tests/lib.rs b/misc/multihash/tests/lib.rs deleted file mode 100644 index f82684325b05..000000000000 --- a/misc/multihash/tests/lib.rs +++ /dev/null @@ -1,122 +0,0 @@ -use parity_multihash::*; - -/// Helper function to convert a hex-encoded byte array back into a bytearray -fn hex_to_bytes(s: &str) -> Vec { - let mut c = 0; - let mut v = Vec::new(); - while c < s.len() { - v.push(u8::from_str_radix(&s[c..c + 2], 16).unwrap()); - c += 2; - } - v -} - -macro_rules! assert_encode { - {$( $alg:ident, $data:expr, $expect:expr; )*} => { - $( - assert_eq!( - encode(Hash::$alg, $data).expect("Must be supported").into_bytes(), - hex_to_bytes($expect), - "{:?} encodes correctly", Hash::$alg - ); - )* - } -} - -#[test] -fn multihash_encode() { - assert_encode! { - SHA1, b"beep boop", "11147c8357577f51d4f0a8d393aa1aaafb28863d9421"; - SHA2256, b"helloworld", "1220936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af"; - SHA2256, b"beep boop", "122090ea688e275d580567325032492b597bc77221c62493e76330b85ddda191ef7c"; - SHA2512, b"hello world", "1340309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"; - SHA3224, b"hello world", "171Cdfb7f18c77e928bb56faeb2da27291bd790bc1045cde45f3210bb6c5"; - SHA3256, b"hello world", "1620644bcc7e564373040999aac89e7622f3ca71fba1d972fd94a31c3bfbf24e3938"; - SHA3384, b"hello world", "153083bff28dde1b1bf5810071c6643c08e5b05bdb836effd70b403ea8ea0a634dc4997eb1053aa3593f590f9c63630dd90b"; - SHA3512, b"hello world", "1440840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a"; - Keccak224, b"hello world", "1A1C25f3ecfebabe99686282f57f5c9e1f18244cfee2813d33f955aae568"; - Keccak256, b"hello world", "1B2047173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"; - Keccak384, b"hello world", "1C3065fc99339a2a40e99d3c40d695b22f278853ca0f925cde4254bcae5e22ece47e6441f91b6568425adc9d95b0072eb49f"; - Keccak512, b"hello world", "1D403ee2b40047b8060f68c67242175660f4174d0af5c01d47168ec20ed619b0b7c42181f40aa1046f39e2ef9efc6910782a998e0013d172458957957fac9405b67d"; - Blake2b512, b"hello world", "c0e40240021ced8799296ceca557832ab941a50b4a11f83478cf141f51f933f653ab9fbcc05a037cddbed06e309bf334942c4e58cdf1a46e237911ccd7fcf9787cbc7fd0"; - Blake2b256, b"hello world", "a0e40220256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610"; - Blake2s256, b"hello world", "e0e402209aec6806794561107e594b1f6a8a6b0c92a0cba9acf5e5e93cca06f781813b0b"; - Blake2s128, b"hello world", "d0e4021037deae0226c30da2ab424a7b8ee14e83"; - } -} - -macro_rules! assert_decode { - {$( $alg:ident, $hash:expr; )*} => { - $( - let hash = hex_to_bytes($hash); - assert_eq!( - MultihashRef::from_slice(&hash).unwrap().algorithm(), - Hash::$alg, - "{:?} decodes correctly", Hash::$alg - ); - )* - } -} - -#[test] -fn assert_decode() { - assert_decode! { - SHA1, "11147c8357577f51d4f0a8d393aa1aaafb28863d9421"; - SHA2256, "1220936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af"; - SHA2256, "122090ea688e275d580567325032492b597bc77221c62493e76330b85ddda191ef7c"; - SHA2512, "1340309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"; - SHA3224, "171Cdfb7f18c77e928bb56faeb2da27291bd790bc1045cde45f3210bb6c5"; - SHA3256, "1620644bcc7e564373040999aac89e7622f3ca71fba1d972fd94a31c3bfbf24e3938"; - SHA3384, "153083bff28dde1b1bf5810071c6643c08e5b05bdb836effd70b403ea8ea0a634dc4997eb1053aa3593f590f9c63630dd90b"; - SHA3512, "1440840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a"; - Keccak224, "1A1C25f3ecfebabe99686282f57f5c9e1f18244cfee2813d33f955aae568"; - Keccak256, "1B2047173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"; - Keccak384, "1C3065fc99339a2a40e99d3c40d695b22f278853ca0f925cde4254bcae5e22ece47e6441f91b6568425adc9d95b0072eb49f"; - Keccak512, "1D403ee2b40047b8060f68c67242175660f4174d0af5c01d47168ec20ed619b0b7c42181f40aa1046f39e2ef9efc6910782a998e0013d172458957957fac9405b67d"; - Blake2b512, "c0e40240021ced8799296ceca557832ab941a50b4a11f83478cf141f51f933f653ab9fbcc05a037cddbed06e309bf334942c4e58cdf1a46e237911ccd7fcf9787cbc7fd0"; - Blake2b256, "a0e40220256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610"; - Blake2s256, "e0e402209aec6806794561107e594b1f6a8a6b0c92a0cba9acf5e5e93cca06f781813b0b"; - Blake2s128, "d0e4021037deae0226c30da2ab424a7b8ee14e83"; - } -} - -macro_rules! assert_roundtrip { - ($( $alg:ident ),*) => { - $( - { - let hash: Vec = encode(Hash::$alg, b"helloworld").unwrap().into_bytes(); - assert_eq!( - MultihashRef::from_slice(&hash).unwrap().algorithm(), - Hash::$alg - ); - } - )* - } -} - -#[test] -fn assert_roundtrip() { - assert_roundtrip!( - SHA1, SHA2256, SHA2512, SHA3224, SHA3256, SHA3384, SHA3512, Keccak224, Keccak256, - Keccak384, Keccak512, Blake2b512, Blake2s256 - ); -} - -#[test] -fn hash_types() { - assert_eq!(Hash::SHA1.size(), 20); - assert_eq!(Hash::SHA2256.size(), 32); - assert_eq!(Hash::SHA2512.size(), 64); - assert_eq!(Hash::SHA3224.size(), 28); - assert_eq!(Hash::SHA3256.size(), 32); - assert_eq!(Hash::SHA3384.size(), 48); - assert_eq!(Hash::SHA3512.size(), 64); - assert_eq!(Hash::Keccak224.size(), 28); - assert_eq!(Hash::Keccak256.size(), 32); - assert_eq!(Hash::Keccak384.size(), 48); - assert_eq!(Hash::Keccak512.size(), 64); - assert_eq!(Hash::Blake2b512.size(), 64); - assert_eq!(Hash::Blake2b256.size(), 32); - assert_eq!(Hash::Blake2s256.size(), 32); - assert_eq!(Hash::Blake2s128.size(), 16); -} diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index ad96881b3bf4..8fd9588d750a 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.1" log = "0.4" libp2p-core = { version = "0.16.0", path = "../../core" } libp2p-swarm = { version = "0.16.0", path = "../../swarm" } -multihash = { package = "parity-multihash", version = "0.2.3", path = "../../misc/multihash" } +multihash = "0.10" prost = "0.6.1" rand = "0.7.2" sha2 = "0.8.0"