Use upstream version of multihash instead of a fork

The changes from the libp2p fork have been backported to upstream, hence
upstream can now be used instead.
This commit is contained in:
Volker Mische 2020-02-26 17:22:26 +01:00
parent 7cbb3cf8f3
commit b00197a0fd
18 changed files with 58 additions and 806 deletions

View File

@ -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",

View File

@ -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.3", 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"

View File

@ -21,7 +21,8 @@
use crate::PublicKey;
use bs58;
use thiserror::Error;
use multihash;
use multihash::{self, Code, Sha2_256};
use rand::Rng;
use std::{convert::TryFrom, borrow::Borrow, fmt, hash, str::FromStr};
/// Public keys with byte-lengths smaller than `MAX_INLINE_KEY_LENGTH` will be
@ -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<Code>) = /*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<u8>) -> Result<PeerId, Vec<u8>> {
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<PeerId, multihash::Multihash> {
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,9 @@ impl PeerId {
///
/// This is useful for randomly walking on a DHT, or for testing purposes.
pub fn random() -> PeerId {
let peer_id = rand::thread_rng().gen::<[u8; 32]>();
PeerId {
multihash: multihash::Multihash::random(multihash::Hash::SHA2256),
multihash: multihash::wrap(multihash::Code::Sha2_256, &peer_id),
canonical: None,
}
}
@ -158,11 +157,7 @@ impl PeerId {
pub fn is_public_key(&self, public_key: &PublicKey) -> Option<bool> {
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 +278,8 @@ mod tests {
#[test]
fn peer_id_identity_equal_to_sha2256() {
let random_bytes = (0..64).map(|_| rand::random::<u8>()).collect::<Vec<u8>>();
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 +289,8 @@ mod tests {
#[test]
fn peer_id_identity_hashes_equal_to_sha2256() {
let random_bytes = (0..64).map(|_| rand::random::<u8>()).collect::<Vec<u8>>();
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 +304,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: Gen>(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<u8>, 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

View File

@ -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"

View File

@ -1,3 +0,0 @@
target
Cargo.lock
*.bk

View File

@ -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

View File

@ -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 <dignifiedquire@gmail.com>", "Parity Technologies <admin@parity.io>"]
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"

View File

@ -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

View File

@ -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<u8>,
}
impl fmt::Display for DecodeOwnedError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.error)
}
}
impl error::Error for DecodeOwnedError {}

View File

@ -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<Hash> {
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,
})
}
}

View File

@ -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<D: digest::Digest>(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<Multihash, EncodeError> {
// 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<B: AsRef<[u8]>>(&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<u8, Self::OutputSize> {
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<B: AsRef<[u8]>>(&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<u8, Self::OutputSize> {
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<u8>) -> Result<Multihash, DecodeOwnedError> {
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<u8> {
self.to_vec()
}
/// Returns the bytes representation of the multihash.
pub fn to_vec(&self) -> Vec<u8> {
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<MultihashRef<'a>> for Multihash {
fn eq(&self, other: &MultihashRef<'a>) -> bool {
&*self.bytes == other.bytes
}
}
impl TryFrom<Vec<u8>> for Multihash {
type Error = DecodeOwnedError;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
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<Self, DecodeError> {
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::<fn(&'_ Hash) -> 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<Multihash> 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());
}
}
}
}

View File

@ -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<u8> {
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<u8> = 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);
}

View File

@ -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"

View File

@ -45,7 +45,7 @@ use libp2p_yamux as yamux;
use quickcheck::*;
use rand::{Rng, random, thread_rng};
use std::{collections::{HashSet, HashMap}, io, num::NonZeroUsize, u64};
use multihash::{Multihash, Hash::SHA2256};
use multihash::{wrap, Code, Multihash};
type TestSwarm = Swarm<Kademlia<MemoryStore>>;
@ -106,6 +106,10 @@ fn build_connected_nodes_with_config(total: usize, step: usize, cfg: KademliaCon
(swarm_ids, swarms)
}
fn random_multihash() -> Multihash {
wrap(Code::Sha2_256, &thread_rng().gen::<[u8; 32]>())
}
#[test]
fn bootstrap() {
fn run(rng: &mut impl Rng) {
@ -302,7 +306,7 @@ fn get_record_not_found() {
swarms[0].add_address(&swarm_ids[1], Protocol::Memory(port_base + 1).into());
swarms[1].add_address(&swarm_ids[2], Protocol::Memory(port_base + 2).into());
let target_key = record::Key::from(Multihash::random(SHA2256));
let target_key = record::Key::from(random_multihash());
swarms[0].get_record(&target_key, Quorum::One);
block_on(
@ -460,7 +464,7 @@ fn get_value() {
swarms[0].add_address(&swarm_ids[1], Protocol::Memory(port_base + 1).into());
swarms[1].add_address(&swarm_ids[2], Protocol::Memory(port_base + 2).into());
let record = Record::new(Multihash::random(SHA2256), vec![4,5,6]);
let record = Record::new(random_multihash(), vec![4,5,6]);
swarms[1].store.put(record.clone()).unwrap();
swarms[0].get_record(&record.key, Quorum::One);
@ -495,7 +499,7 @@ fn get_value_many() {
let (_, mut swarms) = build_connected_nodes(num_nodes, num_nodes);
let num_results = 10;
let record = Record::new(Multihash::random(SHA2256), vec![4,5,6]);
let record = Record::new(random_multihash(), vec![4,5,6]);
for i in 0 .. num_nodes {
swarms[i].store.put(record.clone()).unwrap();

View File

@ -173,7 +173,8 @@ pub struct Distance(pub(super) U256);
mod tests {
use super::*;
use quickcheck::*;
use multihash::Hash::SHA2256;
use multihash::{wrap, Code};
use rand::Rng;
impl Arbitrary for Key<PeerId> {
fn arbitrary<G: Gen>(_: &mut G) -> Key<PeerId> {
@ -183,7 +184,8 @@ mod tests {
impl Arbitrary for Key<Multihash> {
fn arbitrary<G: Gen>(_: &mut G) -> Key<Multihash> {
Key::from(Multihash::random(SHA2256))
let hash = rand::thread_rng().gen::<[u8; 32]>();
Key::from(wrap(Code::Sha2_256, &hash))
}
}

View File

@ -142,13 +142,14 @@ impl ProviderRecord {
mod tests {
use super::*;
use quickcheck::*;
use multihash::Hash::SHA2256;
use multihash::{wrap, Code};
use rand::Rng;
use std::time::Duration;
impl Arbitrary for Key {
fn arbitrary<G: Gen>(_: &mut G) -> Key {
Key::from(Multihash::random(SHA2256))
let hash = rand::thread_rng().gen::<[u8; 32]>();
Key::from(wrap(Code::Sha2_256, &hash))
}
}

View File

@ -215,8 +215,13 @@ impl<'a> RecordStore<'a> for MemoryStore {
#[cfg(test)]
mod tests {
use super::*;
use multihash::Hash::SHA2256;
use multihash::{wrap, Code};
use quickcheck::*;
use rand::Rng;
fn random_multihash() -> Multihash {
wrap(Code::Sha2_256, &rand::thread_rng().gen::<[u8; 32]>())
}
fn distance(r: &ProviderRecord) -> kbucket::Distance {
kbucket::Key::new(r.key.clone())
@ -251,7 +256,7 @@ mod tests {
fn providers_ordered_by_distance_to_key() {
fn prop(providers: Vec<kbucket::Key<PeerId>>) -> bool {
let mut store = MemoryStore::new(PeerId::random());
let key = Key::from(Multihash::random(SHA2256));
let key = Key::from(random_multihash());
let mut records = providers.into_iter().map(|p| {
ProviderRecord::new(key.clone(), p.into_preimage())
@ -274,7 +279,7 @@ mod tests {
fn provided() {
let id = PeerId::random();
let mut store = MemoryStore::new(id.clone());
let key = Multihash::random(SHA2256);
let key = random_multihash();
let rec = ProviderRecord::new(key, id.clone());
assert!(store.add_provider(rec.clone()).is_ok());
assert_eq!(vec![Cow::Borrowed(&rec)], store.provided().collect::<Vec<_>>());
@ -285,7 +290,7 @@ mod tests {
#[test]
fn update_provider() {
let mut store = MemoryStore::new(PeerId::random());
let key = Multihash::random(SHA2256);
let key = random_multihash();
let prv = PeerId::random();
let mut rec = ProviderRecord::new(key, prv);
assert!(store.add_provider(rec.clone()).is_ok());
@ -299,12 +304,12 @@ mod tests {
fn max_provided_keys() {
let mut store = MemoryStore::new(PeerId::random());
for _ in 0 .. store.config.max_provided_keys {
let key = Multihash::random(SHA2256);
let key = random_multihash();
let prv = PeerId::random();
let rec = ProviderRecord::new(key, prv);
let _ = store.add_provider(rec);
}
let key = Multihash::random(SHA2256);
let key = random_multihash();
let prv = PeerId::random();
let rec = ProviderRecord::new(key, prv);
match store.add_provider(rec) {

View File

@ -557,7 +557,7 @@ impl fmt::Debug for MdnsPeer {
#[cfg(test)]
mod tests {
use futures::executor::block_on;
use libp2p_core::{PeerId, multiaddr::multihash::*};
use libp2p_core::{PeerId, multiaddr::multihash};
use std::{io::{Error, ErrorKind}, time::Duration};
use wasm_timer::ext::TryFutureExt;
use crate::service::{MdnsPacket, MdnsService};
@ -646,7 +646,7 @@ mod tests {
#[test]
fn discover_long_peer_id() {
let max_value = String::from_utf8(vec![b'f'; 42]).unwrap();
let hash = encode(Hash::Identity, max_value.as_ref()).unwrap();
let hash = multihash::Identity::digest(max_value.as_ref());
discover(PeerId::from_multihash(hash).unwrap())
}
}