Skip to content

Commit 52f4fd1

Browse files
committed
Merge remote-tracking branch 'upstream/master' into update
Signed-off-by: koushiro <koushiro.cqx@gmail.com>
2 parents 495a09f + 2b8dfe3 commit 52f4fd1

File tree

6 files changed

+785
-503
lines changed

6 files changed

+785
-503
lines changed

benches/multihash.rs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,47 @@
11
use criterion::{black_box, criterion_group, criterion_main, Criterion};
22
use rand::Rng;
33

4-
use multihash::{encode, Hash};
4+
use multihash::{
5+
Blake2b256, Blake2b512, Blake2s128, Blake2s256, Identity, Keccak224, Keccak256, Keccak384,
6+
Keccak512, Sha1, Sha2_256, Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512,
7+
};
58

6-
macro_rules! group_encode {
7-
($criterion:ident, $( $id:expr => $hash:expr, $input:expr)* ) => {{
8-
let mut group = $criterion.benchmark_group("encode");
9+
macro_rules! group_digest {
10+
($criterion:ident, $( $id:expr => $hash:ident, $input:expr)* ) => {{
11+
let mut group = $criterion.benchmark_group("digest");
912
$(
1013
group.bench_function($id, |b| {
1114
b.iter(|| {
12-
let _ = black_box(encode($hash, $input).unwrap());
15+
let _ = black_box($hash::digest($input));
1316
})
1417
});
1518
)*
1619
group.finish();
1720
}};
1821
}
1922

20-
fn bench_encode(c: &mut Criterion) {
23+
fn bench_digest(c: &mut Criterion) {
2124
let mut rng = rand::thread_rng();
2225
let data: Vec<u8> = (0..1024).map(|_| rng.gen()).collect();
23-
group_encode!(c,
24-
"identity" => Hash::Identity, &data
25-
"sha1" => Hash::SHA1, &data
26-
"sha2_256" => Hash::SHA2256, &data
27-
"sha2_512" => Hash::SHA2512, &data
28-
"sha3_224" => Hash::SHA3224, &data
29-
"sha3_256" => Hash::SHA3256, &data
30-
"sha3_384" => Hash::SHA3384, &data
31-
"keccak_224" => Hash::Keccak224, &data
32-
"keccak_256" => Hash::Keccak256, &data
33-
"keccak_384" => Hash::Keccak384, &data
34-
"keccak_512" => Hash::Keccak512, &data
35-
"blake2b_256" => Hash::Blake2b256, &data
36-
"blake2b_512" => Hash::Blake2b512, &data
37-
"blake2s_128" => Hash::Blake2s128, &data
38-
"blake2s_256" => Hash::Blake2s256, &data
26+
group_digest!(c,
27+
"identity" => Identity, &data
28+
"sha1" => Sha1, &data
29+
"sha2_256" => Sha2_256, &data
30+
"sha2_512" => Sha2_512, &data
31+
"sha3_224" => Sha3_224, &data
32+
"sha3_256" => Sha3_256, &data
33+
"sha3_384" => Sha3_384, &data
34+
"sha3_512" => Sha3_512, &data
35+
"keccak_224" => Keccak224, &data
36+
"keccak_256" => Keccak256, &data
37+
"keccak_384" => Keccak384, &data
38+
"keccak_512" => Keccak512, &data
39+
"blake2b_256" => Blake2b256, &data
40+
"blake2b_512" => Blake2b512, &data
41+
"blake2s_128" => Blake2s128, &data
42+
"blake2s_256" => Blake2s256, &data
3943
);
4044
}
4145

42-
criterion_group!(benches, bench_encode);
46+
criterion_group!(benches, bench_digest);
4347
criterion_main!(benches);

src/digests.rs

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
use std::convert::TryFrom;
2+
use std::{cmp, fmt, hash};
3+
4+
use unsigned_varint::{decode as varint_decode, encode as varint_encode};
5+
6+
use crate::errors::{DecodeError, DecodeOwnedError};
7+
use crate::hashes::Code;
8+
use crate::storage::Storage;
9+
10+
/// Represents a valid multihash.
11+
#[derive(Clone)]
12+
pub struct Multihash {
13+
storage: Storage,
14+
}
15+
16+
impl fmt::Debug for Multihash {
17+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18+
f.debug_tuple("Multihash").field(&self.as_bytes()).finish()
19+
}
20+
}
21+
22+
impl PartialEq for Multihash {
23+
fn eq(&self, other: &Self) -> bool {
24+
self.storage.bytes() == other.storage.bytes()
25+
}
26+
}
27+
28+
impl Eq for Multihash {}
29+
30+
impl hash::Hash for Multihash {
31+
fn hash<H: hash::Hasher>(&self, state: &mut H) {
32+
self.storage.bytes().hash(state);
33+
}
34+
}
35+
36+
impl Multihash {
37+
/// Verifies whether `bytes` contains a valid multihash, and if so returns a `Multihash`.
38+
pub fn from_bytes(bytes: Vec<u8>) -> Result<Multihash, DecodeOwnedError> {
39+
if let Err(err) = MultihashRef::from_slice(&bytes) {
40+
return Err(DecodeOwnedError {
41+
error: err,
42+
data: bytes,
43+
});
44+
}
45+
Ok(Multihash {
46+
storage: Storage::from_slice(&bytes),
47+
})
48+
}
49+
50+
/// Returns the bytes representation of the multihash.
51+
pub fn into_bytes(self) -> Vec<u8> {
52+
self.to_vec()
53+
}
54+
55+
/// Returns the bytes representation of the multihash.
56+
pub fn to_vec(&self) -> Vec<u8> {
57+
Vec::from(self.as_bytes())
58+
}
59+
60+
/// Returns the bytes representation of this multihash.
61+
pub fn as_bytes(&self) -> &[u8] {
62+
self.storage.bytes()
63+
}
64+
65+
/// Builds a `MultihashRef` corresponding to this `Multihash`.
66+
pub fn as_ref(&self) -> MultihashRef {
67+
MultihashRef {
68+
bytes: self.as_bytes(),
69+
}
70+
}
71+
72+
/// Returns which hashing algorithm is used in this multihash.
73+
pub fn algorithm(&self) -> Code {
74+
self.as_ref().algorithm()
75+
}
76+
77+
/// Returns the hashed data.
78+
pub fn digest(&self) -> &[u8] {
79+
self.as_ref().digest()
80+
}
81+
}
82+
83+
impl AsRef<[u8]> for Multihash {
84+
fn as_ref(&self) -> &[u8] {
85+
self.as_bytes()
86+
}
87+
}
88+
89+
impl<'a> PartialEq<MultihashRef<'a>> for Multihash {
90+
fn eq(&self, other: &MultihashRef<'a>) -> bool {
91+
&*self.as_bytes() == other.as_bytes()
92+
}
93+
}
94+
95+
impl TryFrom<Vec<u8>> for Multihash {
96+
type Error = DecodeOwnedError;
97+
98+
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
99+
Multihash::from_bytes(value)
100+
}
101+
}
102+
103+
impl PartialOrd for Multihash {
104+
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
105+
Some(self.cmp(other))
106+
}
107+
}
108+
109+
impl Ord for Multihash {
110+
fn cmp(&self, other: &Self) -> cmp::Ordering {
111+
self.as_ref().cmp(&other.as_ref())
112+
}
113+
}
114+
115+
/// Represents a valid multihash.
116+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
117+
pub struct MultihashRef<'a> {
118+
bytes: &'a [u8],
119+
}
120+
121+
impl<'a> MultihashRef<'a> {
122+
/// Creates a `MultihashRef` from the given `input`.
123+
pub fn from_slice(input: &'a [u8]) -> Result<Self, DecodeError> {
124+
if input.is_empty() {
125+
return Err(DecodeError::BadInputLength);
126+
}
127+
128+
let (_code, bytes) = varint_decode::u64(&input).map_err(|_| DecodeError::BadInputLength)?;
129+
130+
let (hash_len, bytes) =
131+
varint_decode::u64(&bytes).map_err(|_| DecodeError::BadInputLength)?;
132+
if (bytes.len() as u64) != hash_len {
133+
return Err(DecodeError::BadInputLength);
134+
}
135+
136+
Ok(MultihashRef { bytes: input })
137+
}
138+
139+
/// Returns which hashing algorithm is used in this multihash.
140+
pub fn algorithm(&self) -> Code {
141+
let (code, _bytes) =
142+
varint_decode::u64(&self.bytes).expect("multihash is known to be valid algorithm");
143+
Code::from_u64(code)
144+
}
145+
146+
/// Returns the hashed data.
147+
pub fn digest(&self) -> &'a [u8] {
148+
let (_code, bytes) =
149+
varint_decode::u64(&self.bytes).expect("multihash is known to be valid digest");
150+
let (_hash_len, bytes) =
151+
varint_decode::u64(&bytes).expect("multihash is known to be a valid digest");
152+
&bytes[..]
153+
}
154+
155+
/// Builds a `Multihash` that owns the data.
156+
///
157+
/// This operation allocates.
158+
pub fn to_owned(&self) -> Multihash {
159+
Multihash {
160+
storage: Storage::from_slice(self.bytes),
161+
}
162+
}
163+
164+
/// Returns the bytes representation of this multihash.
165+
pub fn as_bytes(&self) -> &'a [u8] {
166+
&self.bytes
167+
}
168+
}
169+
170+
impl<'a> PartialEq<Multihash> for MultihashRef<'a> {
171+
fn eq(&self, other: &Multihash) -> bool {
172+
self.as_bytes() == &*other.as_bytes()
173+
}
174+
}
175+
176+
/// The `MultihashDigest` trait specifies an interface common for all multihash functions.
177+
pub trait MultihashDigest {
178+
/// The Mutlihash byte value.
179+
fn code(&self) -> Code;
180+
181+
/// Hash some input and return the digest.
182+
///
183+
/// # Panics
184+
///
185+
/// Panics if the digest length is bigger than 2^32. This only happens for identity hasing.
186+
fn digest(&self, data: &[u8]) -> Multihash;
187+
}
188+
189+
/// Wraps a hash digest in Multihash with the given Mutlihash code.
190+
///
191+
/// The size of the hash is determoned by the size of the input hash. If it should be truncated
192+
/// the input data must already be the truncated hash.
193+
pub fn wrap(code: Code, data: &[u8]) -> Multihash {
194+
let mut code_buf = varint_encode::u64_buffer();
195+
let code = varint_encode::u64(code.to_u64(), &mut code_buf);
196+
197+
let mut size_buf = varint_encode::u64_buffer();
198+
let size = varint_encode::u64(data.len() as u64, &mut size_buf);
199+
200+
Multihash {
201+
storage: Storage::from_slices(&[code, &size, &data]),
202+
}
203+
}

0 commit comments

Comments
 (0)