mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-05-02 14:12:18 +00:00
Remove custom multihash library
This commit is contained in:
parent
932fa6a6b5
commit
ad4b494621
@ -1,6 +1,5 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"multihash",
|
||||
"multistream-select",
|
||||
"datastore",
|
||||
"example",
|
||||
|
@ -23,9 +23,6 @@ Architecture of the crates of this repository:
|
||||
`ConnectionUpgrade` trait of `libp2p-swarm`.
|
||||
- `libp2p-swarm`: Core library that contains all the traits of *libp2p* and plugs things together.
|
||||
- `libp2p-tcp-transport`: Implementation of the `Transport` trait of `libp2p-swarm` for TCP/IP.
|
||||
- `multihash`: Utility library that allows one to represent and manipulate
|
||||
[*multihashes*](https://github.com/multiformats/multihash). A *multihash* is a combination of a
|
||||
hash and its hashing algorithm.
|
||||
- `multistream-select`: Implementation of the `multistream-select` protocol, which is used to
|
||||
negotiate a protocol over a newly-established connection with a peer, or after a connection
|
||||
upgrade.
|
||||
|
@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "multihash"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
hex = "0.2"
|
||||
byteorder = "1.1"
|
@ -1,241 +0,0 @@
|
||||
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
extern crate hex;
|
||||
extern crate byteorder;
|
||||
|
||||
use std::fmt;
|
||||
use std::collections::HashSet;
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use hex::FromHex;
|
||||
|
||||
const ID: u64 = 0x00;
|
||||
const SHA1: u64 = 0x11;
|
||||
const SHA2_256: u64 = 0x12;
|
||||
const SHA2_512: u64 = 0x13;
|
||||
const SHA3_224: u64 = 0x17;
|
||||
const SHA3_256: u64 = 0x16;
|
||||
const SHA3_384: u64 = 0x15;
|
||||
const SHA3_512: u64 = 0x14;
|
||||
const SHA3: u64 = SHA3_512;
|
||||
const KECCAK_224: u64 = 0x1A;
|
||||
const KECCAK_256: u64 = 0x1B;
|
||||
const KECCAK_384: u64 = 0x1C;
|
||||
const KECCAK_512: u64 = 0x1D;
|
||||
const SHAKE_128: u64 = 0x18;
|
||||
const SHAKE_256: u64 = 0x19;
|
||||
const DBL_SHA2_256: u64 = 0x56;
|
||||
const MURMUR3: u64 = 0x22;
|
||||
|
||||
const BLAKE2B_MIN: u64 = 0xb201;
|
||||
const BLAKE2B_MAX: u64 = 0xb240;
|
||||
const BLAKE2S_MIN: u64 = 0xb241;
|
||||
const BLAKE2S_MAX: u64 = 0xb260;
|
||||
|
||||
thread_local! {
|
||||
// Create a static set of CODES that we are willing to accept
|
||||
static CODES: HashSet<u64> = {
|
||||
let mut set = HashSet::new();
|
||||
set.insert(ID);
|
||||
set.insert(SHA1);
|
||||
set.insert(SHA2_256);
|
||||
set.insert(SHA2_512);
|
||||
set.insert(SHA3_224);
|
||||
set.insert(SHA3_256);
|
||||
set.insert(SHA3_384);
|
||||
set.insert(SHA3_512);
|
||||
set.insert(SHA3);
|
||||
set.insert(KECCAK_224);
|
||||
set.insert(KECCAK_256);
|
||||
set.insert(KECCAK_384);
|
||||
set.insert(KECCAK_512);
|
||||
set.insert(SHAKE_128);
|
||||
set.insert(SHAKE_256);
|
||||
set.insert(DBL_SHA2_256);
|
||||
set.insert(MURMUR3);
|
||||
for c in BLAKE2B_MIN..BLAKE2B_MAX { set.insert(c); }
|
||||
for c in BLAKE2S_MIN..BLAKE2S_MAX { set.insert(c); }
|
||||
set
|
||||
};
|
||||
}
|
||||
|
||||
/// Error type for Multihash represents all possible decoding errors from hex string or bytes
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Got invalid input hex
|
||||
FromHexError,
|
||||
/// Couldn't parse the code from bytes
|
||||
UnreadableCode,
|
||||
/// The code parsed (given in argument) isn't a known code for any hash
|
||||
UnknownCode(u64),
|
||||
/// Couldn't parse the length from bytes
|
||||
UnreadableLength,
|
||||
/// The length provided (found in first argument) doesn't match the actual
|
||||
/// length of the input digest (given in second argument).
|
||||
InvalidLength(u64, usize),
|
||||
}
|
||||
|
||||
/// Multihash is a structure for tagging a hash with some meta data,
|
||||
/// such as its type and length. This facilitiates reading them over
|
||||
/// (for instance) a network stream. The format is as follows:
|
||||
/// <hash function code><digest size><hash function output>
|
||||
/// See the spec for more information.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||
pub struct Multihash {
|
||||
/// The code of the hash algorithm in question
|
||||
code: u64,
|
||||
/// Length of the digest byte vector
|
||||
length: u64,
|
||||
/// Raw bytes of the hash digest
|
||||
digest: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Display of a Multihash prints the "raw" hex string, including code and length
|
||||
impl fmt::Display for Multihash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:016x}{:016x}", self.code, self.length)?;
|
||||
for x in &self.digest {
|
||||
write!(f, "{:02x}", x)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// FromHex implementation is provided along with `Multihash::decode_hex_string` in case
|
||||
/// someone already has FromHex imported and they would prefer to use that for some reason
|
||||
impl FromHex for Multihash {
|
||||
type Error = Error;
|
||||
fn from_hex<T: AsRef<[u8]>>(s: T) -> Result<Self, Self::Error> {
|
||||
let bs = Vec::from_hex(s).map_err(|_| Error::FromHexError)?;
|
||||
Self::decode_bytes(bs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Multihash {
|
||||
/// Returns a byte vec representing the encoded multihash
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut v = Vec::new();
|
||||
v.write_u64::<BigEndian>(self.code).expect("writing to a locally owned vec should never yield I/O errors");
|
||||
v.write_u64::<BigEndian>(self.length).expect("writing to a locally owned vec should never yield I/O errors");
|
||||
v.extend_from_slice(&self.digest);
|
||||
v
|
||||
}
|
||||
|
||||
/// Takes a code for a digest type and a vec of bytes of the digest and returns a Multihash
|
||||
pub fn encode_bytes(code: u64, bytes: Vec<u8>) -> Result<Multihash, Error> {
|
||||
if !Multihash::valid_code(&code) {
|
||||
return Err(Error::UnknownCode(code));
|
||||
}
|
||||
Ok(Multihash {
|
||||
code: code,
|
||||
length: bytes.len() as u64,
|
||||
digest: bytes
|
||||
})
|
||||
}
|
||||
|
||||
/// Takes a code for a digest type and a hex string of the digest and returns a Multihash
|
||||
pub fn encode_hex_string(code: u64, hex: String) -> Result<Multihash, Error> {
|
||||
let bytes = Vec::from_hex(&hex).map_err(|_| Error::FromHexError)?;
|
||||
Self::encode_bytes(code, bytes)
|
||||
}
|
||||
|
||||
/// Decode a vec of bytes into a Multihash, consuming the vec in the process
|
||||
pub fn decode_bytes(bytes: Vec<u8>) -> Result<Multihash, Error> {
|
||||
let mut rdr = bytes.as_slice();
|
||||
let code = rdr.read_u64::<BigEndian>().map_err(|_| Error::UnreadableCode)?;
|
||||
let length = rdr.read_u64::<BigEndian>().map_err(|_| Error::UnreadableLength)?;
|
||||
let bytes = rdr.to_vec();
|
||||
|
||||
if !Multihash::valid_code(&code) {
|
||||
return Err(Error::UnknownCode(code));
|
||||
}
|
||||
if bytes.len() != length as usize {
|
||||
return Err(Error::InvalidLength(length, bytes.len()));
|
||||
}
|
||||
|
||||
Ok(Multihash {
|
||||
code: code,
|
||||
length: length,
|
||||
digest: bytes
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert a hex string to a Multihash
|
||||
pub fn decode_hex_string<T: AsRef<[u8]>>(s: T) -> Result<Multihash, Error> {
|
||||
/// Using this here to not have to reexport the hex::FromHex trait
|
||||
Multihash::from_hex(s)
|
||||
}
|
||||
|
||||
/// Checks if the given code is a valid code for multihash
|
||||
pub fn valid_code(c: &u64) -> bool {
|
||||
CODES.with(|codes| codes.contains(c))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Multihash};
|
||||
|
||||
#[test]
|
||||
fn multihash_can_be_displayed() {
|
||||
let hash = Multihash { code: 0x11, length: 3, digest: vec![42, 0, 255]};
|
||||
assert_eq!(format!("{}", hash), "000000000000001100000000000000032a00ff");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn produces_correct_vec_of_bytes() {
|
||||
let digest_bytes = vec![44, 38, 180, 107, 104, 255, 198, 143, 249, 155, 69, 60, 29, 48, 65, 52, 19, 66, 45, 112, 100, 131, 191, 160, 249, 138, 94, 136, 98, 102, 231, 174];
|
||||
let hash = Multihash {
|
||||
code: 0x00,
|
||||
length: digest_bytes.len() as u64,
|
||||
digest: digest_bytes
|
||||
};
|
||||
let expected_bytes = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 44, 38, 180, 107, 104, 255, 198, 143, 249, 155, 69, 60, 29, 48, 65, 52, 19, 66, 45, 112, 100, 131, 191, 160, 249, 138, 94, 136, 98, 102, 231, 174];
|
||||
|
||||
assert_eq!(hash.to_bytes(), expected_bytes);
|
||||
|
||||
assert_eq!(Multihash::decode_bytes(expected_bytes).unwrap(), hash);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encoding_hashes() {
|
||||
let hex_string = "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae";
|
||||
let hash = Multihash::encode_hex_string(0x00, hex_string.to_owned()).unwrap();
|
||||
let expected_bytes = vec![44,38,180,107,104,255,198,143,249,155,69,60,29,48,65,52,19,66,45,112,100,131,191,160,249,138,94,136,98,102,231,174];
|
||||
assert_eq!(hash, Multihash {
|
||||
code: 0x00,
|
||||
length: expected_bytes.len() as u64,
|
||||
digest: expected_bytes
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decoding_hashes() {
|
||||
let hex_string = "000000000000000000000000000000202c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae";
|
||||
let hash = Multihash::decode_hex_string(hex_string).unwrap();
|
||||
let expected_bytes = vec![44,38,180,107,104,255,198,143,249,155,69,60,29,48,65,52,19,66,45,112,100,131,191,160,249,138,94,136,98,102,231,174];
|
||||
assert_eq!(hash, Multihash {
|
||||
code: 0x00,
|
||||
length: expected_bytes.len() as u64,
|
||||
digest: expected_bytes
|
||||
});
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user