mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-04-25 11:02:12 +00:00
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:
parent
7cbb3cf8f3
commit
b00197a0fd
@ -17,7 +17,7 @@ secp256k1 = ["libp2p-core/secp256k1", "libp2p-secio/secp256k1"]
|
|||||||
bytes = "0.5"
|
bytes = "0.5"
|
||||||
futures = "0.3.1"
|
futures = "0.3.1"
|
||||||
multiaddr = { package = "parity-multiaddr", version = "0.7.2", path = "misc/multiaddr" }
|
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"
|
lazy_static = "1.2"
|
||||||
libp2p-mplex = { version = "0.16.0", path = "muxers/mplex" }
|
libp2p-mplex = { version = "0.16.0", path = "muxers/mplex" }
|
||||||
libp2p-identify = { version = "0.16.0", path = "protocols/identify" }
|
libp2p-identify = { version = "0.16.0", path = "protocols/identify" }
|
||||||
@ -56,7 +56,6 @@ members = [
|
|||||||
"core",
|
"core",
|
||||||
"misc/core-derive",
|
"misc/core-derive",
|
||||||
"misc/multiaddr",
|
"misc/multiaddr",
|
||||||
"misc/multihash",
|
|
||||||
"misc/multistream-select",
|
"misc/multistream-select",
|
||||||
"misc/peer-id-generator",
|
"misc/peer-id-generator",
|
||||||
"muxers/mplex",
|
"muxers/mplex",
|
||||||
|
@ -20,7 +20,7 @@ lazy_static = "1.2"
|
|||||||
libsecp256k1 = { version = "0.3.1", optional = true }
|
libsecp256k1 = { version = "0.3.1", optional = true }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
multiaddr = { package = "parity-multiaddr", version = "0.7.3", path = "../misc/multiaddr" }
|
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" }
|
multistream-select = { version = "0.7.0", path = "../misc/multistream-select" }
|
||||||
parking_lot = "0.10.0"
|
parking_lot = "0.10.0"
|
||||||
pin-project = "0.4.6"
|
pin-project = "0.4.6"
|
||||||
|
@ -21,7 +21,8 @@
|
|||||||
use crate::PublicKey;
|
use crate::PublicKey;
|
||||||
use bs58;
|
use bs58;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use multihash;
|
use multihash::{self, Code, Sha2_256};
|
||||||
|
use rand::Rng;
|
||||||
use std::{convert::TryFrom, borrow::Borrow, fmt, hash, str::FromStr};
|
use std::{convert::TryFrom, borrow::Borrow, fmt, hash, str::FromStr};
|
||||||
|
|
||||||
/// Public keys with byte-lengths smaller than `MAX_INLINE_KEY_LENGTH` will be
|
/// 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).
|
// 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.
|
// 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.
|
// 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))
|
(multihash::Hash::Identity, Some(multihash::Hash::SHA2256))
|
||||||
} else {*/
|
} else {*/
|
||||||
(multihash::Hash::SHA2256, None);
|
(Code::Sha2_256, None);
|
||||||
//};
|
//};
|
||||||
|
|
||||||
let canonical = canonical_algorithm.map(|alg|
|
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)
|
let multihash = hash_algorithm.hasher().expect("hasher exists").digest(&key_enc);
|
||||||
.expect("identity and sha2-256 are always supported by known public key types");
|
|
||||||
|
|
||||||
PeerId { multihash, canonical }
|
PeerId { multihash, canonical }
|
||||||
}
|
}
|
||||||
@ -89,12 +89,11 @@ impl PeerId {
|
|||||||
pub fn from_bytes(data: Vec<u8>) -> Result<PeerId, Vec<u8>> {
|
pub fn from_bytes(data: Vec<u8>) -> Result<PeerId, Vec<u8>> {
|
||||||
match multihash::Multihash::from_bytes(data) {
|
match multihash::Multihash::from_bytes(data) {
|
||||||
Ok(multihash) => {
|
Ok(multihash) => {
|
||||||
if multihash.algorithm() == multihash::Hash::SHA2256 {
|
if multihash.algorithm() == multihash::Code::Sha2_256 {
|
||||||
Ok(PeerId { multihash, canonical: None })
|
Ok(PeerId { multihash, canonical: None })
|
||||||
}
|
}
|
||||||
else if multihash.algorithm() == multihash::Hash::Identity {
|
else if multihash.algorithm() == multihash::Code::Identity {
|
||||||
let canonical = multihash::encode(multihash::Hash::SHA2256, multihash.digest())
|
let canonical = Sha2_256::digest(&multihash.digest());
|
||||||
.expect("SHA2256 is always supported");
|
|
||||||
Ok(PeerId { multihash, canonical: Some(canonical) })
|
Ok(PeerId { multihash, canonical: Some(canonical) })
|
||||||
} else {
|
} else {
|
||||||
Err(multihash.into_bytes())
|
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,
|
/// Turns a `Multihash` into a `PeerId`. If the multihash doesn't use the correct algorithm,
|
||||||
/// returns back the data as an error.
|
/// returns back the data as an error.
|
||||||
pub fn from_multihash(data: multihash::Multihash) -> Result<PeerId, multihash::Multihash> {
|
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 })
|
Ok(PeerId { multihash: data, canonical: None })
|
||||||
} else if data.algorithm() == multihash::Hash::Identity {
|
} else if data.algorithm() == multihash::Code::Identity {
|
||||||
let canonical = multihash::encode(multihash::Hash::SHA2256, data.digest())
|
let canonical = Sha2_256::digest(data.digest());
|
||||||
.expect("SHA2256 is always supported");
|
|
||||||
Ok(PeerId { multihash: data, canonical: Some(canonical) })
|
Ok(PeerId { multihash: data, canonical: Some(canonical) })
|
||||||
} else {
|
} else {
|
||||||
Err(data)
|
Err(data)
|
||||||
@ -122,8 +120,9 @@ impl PeerId {
|
|||||||
///
|
///
|
||||||
/// This is useful for randomly walking on a DHT, or for testing purposes.
|
/// This is useful for randomly walking on a DHT, or for testing purposes.
|
||||||
pub fn random() -> PeerId {
|
pub fn random() -> PeerId {
|
||||||
|
let peer_id = rand::thread_rng().gen::<[u8; 32]>();
|
||||||
PeerId {
|
PeerId {
|
||||||
multihash: multihash::Multihash::random(multihash::Hash::SHA2256),
|
multihash: multihash::wrap(multihash::Code::Sha2_256, &peer_id),
|
||||||
canonical: None,
|
canonical: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,11 +157,7 @@ impl PeerId {
|
|||||||
pub fn is_public_key(&self, public_key: &PublicKey) -> Option<bool> {
|
pub fn is_public_key(&self, public_key: &PublicKey) -> Option<bool> {
|
||||||
let alg = self.multihash.algorithm();
|
let alg = self.multihash.algorithm();
|
||||||
let enc = public_key.clone().into_protobuf_encoding();
|
let enc = public_key.clone().into_protobuf_encoding();
|
||||||
match multihash::encode(alg, &enc) {
|
Some(alg.hasher()?.digest(&enc) == self.multihash)
|
||||||
Ok(h) => Some(h == self.multihash),
|
|
||||||
Err(multihash::EncodeError::UnsupportedType) => None,
|
|
||||||
Err(multihash::EncodeError::UnsupportedInputLength) => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,8 +278,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn peer_id_identity_equal_to_sha2256() {
|
fn peer_id_identity_equal_to_sha2256() {
|
||||||
let random_bytes = (0..64).map(|_| rand::random::<u8>()).collect::<Vec<u8>>();
|
let random_bytes = (0..64).map(|_| rand::random::<u8>()).collect::<Vec<u8>>();
|
||||||
let mh1 = multihash::encode(multihash::Hash::SHA2256, &random_bytes).unwrap();
|
let mh1 = multihash::Sha2_256::digest(&random_bytes);
|
||||||
let mh2 = multihash::encode(multihash::Hash::Identity, &random_bytes).unwrap();
|
let mh2 = multihash::Identity::digest(&random_bytes);
|
||||||
let peer_id1 = PeerId::try_from(mh1).unwrap();
|
let peer_id1 = PeerId::try_from(mh1).unwrap();
|
||||||
let peer_id2 = PeerId::try_from(mh2).unwrap();
|
let peer_id2 = PeerId::try_from(mh2).unwrap();
|
||||||
assert_eq!(peer_id1, peer_id2);
|
assert_eq!(peer_id1, peer_id2);
|
||||||
@ -294,8 +289,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn peer_id_identity_hashes_equal_to_sha2256() {
|
fn peer_id_identity_hashes_equal_to_sha2256() {
|
||||||
let random_bytes = (0..64).map(|_| rand::random::<u8>()).collect::<Vec<u8>>();
|
let random_bytes = (0..64).map(|_| rand::random::<u8>()).collect::<Vec<u8>>();
|
||||||
let mh1 = multihash::encode(multihash::Hash::SHA2256, &random_bytes).unwrap();
|
let mh1 = multihash::Sha2_256::digest(&random_bytes);
|
||||||
let mh2 = multihash::encode(multihash::Hash::Identity, &random_bytes).unwrap();
|
let mh2 = multihash::Identity::digest(&random_bytes);
|
||||||
let peer_id1 = PeerId::try_from(mh1).unwrap();
|
let peer_id1 = PeerId::try_from(mh1).unwrap();
|
||||||
let peer_id2 = PeerId::try_from(mh2).unwrap();
|
let peer_id2 = PeerId::try_from(mh2).unwrap();
|
||||||
|
|
||||||
@ -309,26 +304,26 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn peer_id_equal_across_algorithms() {
|
fn peer_id_equal_across_algorithms() {
|
||||||
use multihash::Hash;
|
use multihash::Code;
|
||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
struct HashAlgo(Hash);
|
struct HashAlgo(Code);
|
||||||
|
|
||||||
impl Arbitrary for HashAlgo {
|
impl Arbitrary for HashAlgo {
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
||||||
match g.next_u32() % 4 { // make Hash::Identity more likely
|
match g.next_u32() % 4 { // make Hash::Identity more likely
|
||||||
0 => HashAlgo(Hash::SHA2256),
|
0 => HashAlgo(Code::Sha2_256),
|
||||||
_ => HashAlgo(Hash::Identity)
|
_ => HashAlgo(Code::Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn property(data: Vec<u8>, algo1: HashAlgo, algo2: HashAlgo) -> bool {
|
fn property(data: Vec<u8>, algo1: HashAlgo, algo2: HashAlgo) -> bool {
|
||||||
let a = PeerId::try_from(multihash::encode(algo1.0, &data).unwrap()).unwrap();
|
let a = PeerId::try_from(algo1.0.hasher().unwrap().digest(&data)).unwrap();
|
||||||
let b = PeerId::try_from(multihash::encode(algo2.0, &data).unwrap()).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
|
a == b
|
||||||
} else {
|
} else {
|
||||||
a != b
|
a != b
|
||||||
|
@ -13,7 +13,7 @@ arrayref = "0.3"
|
|||||||
bs58 = "0.3.0"
|
bs58 = "0.3.0"
|
||||||
byteorder = "1.3.1"
|
byteorder = "1.3.1"
|
||||||
data-encoding = "2.1"
|
data-encoding = "2.1"
|
||||||
multihash = { package = "parity-multihash", version = "0.2.1", path = "../multihash" }
|
multihash = "0.10"
|
||||||
percent-encoding = "2.1.0"
|
percent-encoding = "2.1.0"
|
||||||
serde = "1.0.70"
|
serde = "1.0.70"
|
||||||
static_assertions = "1.1"
|
static_assertions = "1.1"
|
||||||
|
3
misc/multihash/.gitignore
vendored
3
misc/multihash/.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
target
|
|
||||||
Cargo.lock
|
|
||||||
*.bk
|
|
@ -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
|
|
@ -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"
|
|
@ -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
|
|
@ -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 {}
|
|
@ -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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -19,7 +19,7 @@ futures = "0.3.1"
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
libp2p-core = { version = "0.16.0", path = "../../core" }
|
libp2p-core = { version = "0.16.0", path = "../../core" }
|
||||||
libp2p-swarm = { version = "0.16.0", path = "../../swarm" }
|
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"
|
prost = "0.6.1"
|
||||||
rand = "0.7.2"
|
rand = "0.7.2"
|
||||||
sha2 = "0.8.0"
|
sha2 = "0.8.0"
|
||||||
|
@ -45,7 +45,7 @@ use libp2p_yamux as yamux;
|
|||||||
use quickcheck::*;
|
use quickcheck::*;
|
||||||
use rand::{Rng, random, thread_rng};
|
use rand::{Rng, random, thread_rng};
|
||||||
use std::{collections::{HashSet, HashMap}, io, num::NonZeroUsize, u64};
|
use std::{collections::{HashSet, HashMap}, io, num::NonZeroUsize, u64};
|
||||||
use multihash::{Multihash, Hash::SHA2256};
|
use multihash::{wrap, Code, Multihash};
|
||||||
|
|
||||||
type TestSwarm = Swarm<Kademlia<MemoryStore>>;
|
type TestSwarm = Swarm<Kademlia<MemoryStore>>;
|
||||||
|
|
||||||
@ -106,6 +106,10 @@ fn build_connected_nodes_with_config(total: usize, step: usize, cfg: KademliaCon
|
|||||||
(swarm_ids, swarms)
|
(swarm_ids, swarms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn random_multihash() -> Multihash {
|
||||||
|
wrap(Code::Sha2_256, &thread_rng().gen::<[u8; 32]>())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bootstrap() {
|
fn bootstrap() {
|
||||||
fn run(rng: &mut impl Rng) {
|
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[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());
|
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);
|
swarms[0].get_record(&target_key, Quorum::One);
|
||||||
|
|
||||||
block_on(
|
block_on(
|
||||||
@ -460,7 +464,7 @@ fn get_value() {
|
|||||||
swarms[0].add_address(&swarm_ids[1], Protocol::Memory(port_base + 1).into());
|
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());
|
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[1].store.put(record.clone()).unwrap();
|
||||||
swarms[0].get_record(&record.key, Quorum::One);
|
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 (_, mut swarms) = build_connected_nodes(num_nodes, num_nodes);
|
||||||
let num_results = 10;
|
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 {
|
for i in 0 .. num_nodes {
|
||||||
swarms[i].store.put(record.clone()).unwrap();
|
swarms[i].store.put(record.clone()).unwrap();
|
||||||
|
@ -173,7 +173,8 @@ pub struct Distance(pub(super) U256);
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use quickcheck::*;
|
use quickcheck::*;
|
||||||
use multihash::Hash::SHA2256;
|
use multihash::{wrap, Code};
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
impl Arbitrary for Key<PeerId> {
|
impl Arbitrary for Key<PeerId> {
|
||||||
fn arbitrary<G: Gen>(_: &mut G) -> Key<PeerId> {
|
fn arbitrary<G: Gen>(_: &mut G) -> Key<PeerId> {
|
||||||
@ -183,7 +184,8 @@ mod tests {
|
|||||||
|
|
||||||
impl Arbitrary for Key<Multihash> {
|
impl Arbitrary for Key<Multihash> {
|
||||||
fn arbitrary<G: Gen>(_: &mut G) -> 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,13 +142,14 @@ impl ProviderRecord {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use quickcheck::*;
|
use quickcheck::*;
|
||||||
use multihash::Hash::SHA2256;
|
use multihash::{wrap, Code};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
impl Arbitrary for Key {
|
impl Arbitrary for Key {
|
||||||
fn arbitrary<G: Gen>(_: &mut G) -> 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,8 +215,13 @@ impl<'a> RecordStore<'a> for MemoryStore {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use multihash::Hash::SHA2256;
|
use multihash::{wrap, Code};
|
||||||
use quickcheck::*;
|
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 {
|
fn distance(r: &ProviderRecord) -> kbucket::Distance {
|
||||||
kbucket::Key::new(r.key.clone())
|
kbucket::Key::new(r.key.clone())
|
||||||
@ -251,7 +256,7 @@ mod tests {
|
|||||||
fn providers_ordered_by_distance_to_key() {
|
fn providers_ordered_by_distance_to_key() {
|
||||||
fn prop(providers: Vec<kbucket::Key<PeerId>>) -> bool {
|
fn prop(providers: Vec<kbucket::Key<PeerId>>) -> bool {
|
||||||
let mut store = MemoryStore::new(PeerId::random());
|
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| {
|
let mut records = providers.into_iter().map(|p| {
|
||||||
ProviderRecord::new(key.clone(), p.into_preimage())
|
ProviderRecord::new(key.clone(), p.into_preimage())
|
||||||
@ -274,7 +279,7 @@ mod tests {
|
|||||||
fn provided() {
|
fn provided() {
|
||||||
let id = PeerId::random();
|
let id = PeerId::random();
|
||||||
let mut store = MemoryStore::new(id.clone());
|
let mut store = MemoryStore::new(id.clone());
|
||||||
let key = Multihash::random(SHA2256);
|
let key = random_multihash();
|
||||||
let rec = ProviderRecord::new(key, id.clone());
|
let rec = ProviderRecord::new(key, id.clone());
|
||||||
assert!(store.add_provider(rec.clone()).is_ok());
|
assert!(store.add_provider(rec.clone()).is_ok());
|
||||||
assert_eq!(vec![Cow::Borrowed(&rec)], store.provided().collect::<Vec<_>>());
|
assert_eq!(vec![Cow::Borrowed(&rec)], store.provided().collect::<Vec<_>>());
|
||||||
@ -285,7 +290,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn update_provider() {
|
fn update_provider() {
|
||||||
let mut store = MemoryStore::new(PeerId::random());
|
let mut store = MemoryStore::new(PeerId::random());
|
||||||
let key = Multihash::random(SHA2256);
|
let key = random_multihash();
|
||||||
let prv = PeerId::random();
|
let prv = PeerId::random();
|
||||||
let mut rec = ProviderRecord::new(key, prv);
|
let mut rec = ProviderRecord::new(key, prv);
|
||||||
assert!(store.add_provider(rec.clone()).is_ok());
|
assert!(store.add_provider(rec.clone()).is_ok());
|
||||||
@ -299,12 +304,12 @@ mod tests {
|
|||||||
fn max_provided_keys() {
|
fn max_provided_keys() {
|
||||||
let mut store = MemoryStore::new(PeerId::random());
|
let mut store = MemoryStore::new(PeerId::random());
|
||||||
for _ in 0 .. store.config.max_provided_keys {
|
for _ in 0 .. store.config.max_provided_keys {
|
||||||
let key = Multihash::random(SHA2256);
|
let key = random_multihash();
|
||||||
let prv = PeerId::random();
|
let prv = PeerId::random();
|
||||||
let rec = ProviderRecord::new(key, prv);
|
let rec = ProviderRecord::new(key, prv);
|
||||||
let _ = store.add_provider(rec);
|
let _ = store.add_provider(rec);
|
||||||
}
|
}
|
||||||
let key = Multihash::random(SHA2256);
|
let key = random_multihash();
|
||||||
let prv = PeerId::random();
|
let prv = PeerId::random();
|
||||||
let rec = ProviderRecord::new(key, prv);
|
let rec = ProviderRecord::new(key, prv);
|
||||||
match store.add_provider(rec) {
|
match store.add_provider(rec) {
|
||||||
|
@ -557,7 +557,7 @@ impl fmt::Debug for MdnsPeer {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use futures::executor::block_on;
|
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 std::{io::{Error, ErrorKind}, time::Duration};
|
||||||
use wasm_timer::ext::TryFutureExt;
|
use wasm_timer::ext::TryFutureExt;
|
||||||
use crate::service::{MdnsPacket, MdnsService};
|
use crate::service::{MdnsPacket, MdnsService};
|
||||||
@ -646,7 +646,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn discover_long_peer_id() {
|
fn discover_long_peer_id() {
|
||||||
let max_value = String::from_utf8(vec![b'f'; 42]).unwrap();
|
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())
|
discover(PeerId::from_multihash(hash).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user