parity_multihash/
lib.rs

1//! # Multihash
2//!
3//! Implementation of [multihash](https://github.com/multiformats/multihash) in Rust.
4//!
5//! A `Multihash` is a structure that contains a hashing algorithm, plus some hashed data.
6//! A `MultihashRef` is the same as a `Multihash`, except that it doesn't own its data.
7
8mod errors;
9mod hashes;
10
11use std::{convert::TryFrom, fmt::Write};
12
13use bytes::{BufMut, Bytes, BytesMut};
14use rand::RngCore;
15use sha2::digest::{self, VariableOutput};
16use std::borrow::Borrow;
17use unsigned_varint::{decode, encode};
18
19pub use self::errors::{DecodeError, DecodeOwnedError, EncodeError};
20pub use self::hashes::Hash;
21
22/// Helper function for encoding input into output using given `Digest`
23fn digest_encode<D: digest::Digest>(input: &[u8], output: &mut [u8]) {
24    output.copy_from_slice(&D::digest(input))
25}
26
27// And another one to keep the matching DRY
28macro_rules! match_encoder {
29    ($hash_id:ident for ($input:expr, $output:expr) {
30        $( $hashtype:ident => $hash_ty:path, )*
31    }) => ({
32        match $hash_id {
33            $(
34                Hash::$hashtype => digest_encode::<$hash_ty>($input, $output),
35            )*
36
37            _ => return Err(EncodeError::UnsupportedType)
38        }
39    })
40}
41
42/// Encodes data into a multihash.
43///
44/// # Errors
45///
46/// Will return an error if the specified hash type is not supported. See the docs for `Hash`
47/// to see what is supported.
48///
49/// # Examples
50///
51/// ```
52/// use parity_multihash::{encode, Hash};
53///
54/// assert_eq!(
55///     encode(Hash::SHA2256, b"hello world").unwrap().to_vec(),
56///     vec![18, 32, 185, 77, 39, 185, 147, 77, 62, 8, 165, 46, 82, 215, 218, 125, 171, 250, 196,
57///     132, 239, 227, 122, 83, 128, 238, 144, 136, 247, 172, 226, 239, 205, 233]
58/// );
59/// ```
60///
61pub fn encode(hash: Hash, input: &[u8]) -> Result<Multihash, EncodeError> {
62    // Custom length encoding for the identity multihash
63    if let Hash::Identity = hash {
64        if u64::from(std::u32::MAX) < as_u64(input.len()) {
65            return Err(EncodeError::UnsupportedInputLength);
66        }
67        let mut buf = encode::u16_buffer();
68        let code = encode::u16(hash.code(), &mut buf);
69        let mut len_buf = encode::u32_buffer();
70        let size = encode::u32(input.len() as u32, &mut len_buf);
71
72        let total_len = code.len() + size.len() + input.len();
73
74        let mut output = BytesMut::with_capacity(total_len);
75        output.put_slice(code);
76        output.put_slice(size);
77        output.put_slice(input);
78        Ok(Multihash {
79            bytes: output.freeze(),
80        })
81    } else {
82        let (offset, mut output) = encode_hash(hash);
83        match_encoder!(hash for (input, &mut output[offset ..]) {
84            SHA1 => sha1::Sha1,
85            SHA2256 => sha2::Sha256,
86            SHA2512 => sha2::Sha512,
87            SHA3224 => sha3::Sha3_224,
88            SHA3256 => sha3::Sha3_256,
89            SHA3384 => sha3::Sha3_384,
90            SHA3512 => sha3::Sha3_512,
91            Keccak224 => sha3::Keccak224,
92            Keccak256 => sha3::Keccak256,
93            Keccak384 => sha3::Keccak384,
94            Keccak512 => sha3::Keccak512,
95            Blake2b512 => blake2::Blake2b,
96            Blake2b256 => Blake2b256,
97            Blake2s256 => blake2::Blake2s,
98            Blake2s128 => Blake2s128,
99        });
100        Ok(Multihash {
101            bytes: output.freeze(),
102        })
103    }
104}
105
106// Encode the given [`Hash`] value and ensure the returned [`BytesMut`]
107// has enough capacity to hold the actual digest.
108fn encode_hash(hash: Hash) -> (usize, BytesMut) {
109    let mut buf = encode::u16_buffer();
110    let code = encode::u16(hash.code(), &mut buf);
111
112    let len = code.len() + 1 + usize::from(hash.size());
113
114    let mut output = BytesMut::with_capacity(len);
115    output.put_slice(code);
116    output.put_u8(hash.size());
117    output.resize(len, 0);
118
119    (code.len() + 1, output)
120}
121
122/// BLAKE2b-256 (32-byte hash size)
123#[derive(Debug, Clone)]
124struct Blake2b256(blake2::VarBlake2b);
125
126impl Default for Blake2b256 {
127    fn default() -> Self {
128        Blake2b256(blake2::VarBlake2b::new(32).unwrap())
129    }
130}
131
132impl digest::Input for Blake2b256 {
133    fn input<B: AsRef<[u8]>>(&mut self, data: B) {
134        self.0.input(data)
135    }
136}
137
138impl digest::FixedOutput for Blake2b256 {
139    type OutputSize = digest::generic_array::typenum::U32;
140
141    fn fixed_result(self) -> digest::generic_array::GenericArray<u8, Self::OutputSize> {
142        let mut out = digest::generic_array::GenericArray::default();
143        self.0.variable_result(|slice| {
144            assert_eq!(slice.len(), 32);
145            out.copy_from_slice(slice)
146        });
147        out
148    }
149}
150
151impl digest::Reset for Blake2b256 {
152    fn reset(&mut self) {
153        self.0.reset()
154    }
155}
156
157/// BLAKE2s-128 (16-byte hash size)
158#[derive(Debug, Clone)]
159struct Blake2s128(blake2::VarBlake2s);
160
161impl Default for Blake2s128 {
162    fn default() -> Self {
163        Blake2s128(blake2::VarBlake2s::new(16).unwrap())
164    }
165}
166
167impl digest::Input for Blake2s128 {
168    fn input<B: AsRef<[u8]>>(&mut self, data: B) {
169        self.0.input(data)
170    }
171}
172
173impl digest::FixedOutput for Blake2s128 {
174    type OutputSize = digest::generic_array::typenum::U16;
175
176    fn fixed_result(self) -> digest::generic_array::GenericArray<u8, Self::OutputSize> {
177        let mut out = digest::generic_array::GenericArray::default();
178        self.0.variable_result(|slice| {
179            assert_eq!(slice.len(), 16);
180            out.copy_from_slice(slice)
181        });
182        out
183    }
184}
185
186impl digest::Reset for Blake2s128 {
187    fn reset(&mut self) {
188        self.0.reset()
189    }
190}
191
192/// Represents a valid multihash.
193#[derive(Debug, Clone, PartialEq, Eq, Hash)]
194pub struct Multihash { bytes: Bytes }
195
196impl Multihash {
197    /// Verifies whether `bytes` contains a valid multihash, and if so returns a `Multihash`.
198    pub fn from_bytes(bytes: Vec<u8>) -> Result<Multihash, DecodeOwnedError> {
199        if let Err(err) = MultihashRef::from_slice(&bytes) {
200            return Err(DecodeOwnedError { error: err, data: bytes });
201        }
202        Ok(Multihash { bytes: Bytes::from(bytes) })
203    }
204
205    /// Generates a random `Multihash` from a cryptographically secure PRNG.
206    pub fn random(hash: Hash) -> Multihash {
207        let (offset, mut bytes) = encode_hash(hash);
208        rand::thread_rng().fill_bytes(&mut bytes[offset ..]);
209        Multihash { bytes: bytes.freeze() }
210    }
211
212    /// Returns the bytes representation of the multihash.
213    pub fn into_bytes(self) -> Vec<u8> {
214        self.to_vec()
215    }
216
217    /// Returns the bytes representation of the multihash.
218    pub fn to_vec(&self) -> Vec<u8> {
219        Vec::from(&self.bytes[..])
220    }
221
222    /// Returns the bytes representation of this multihash.
223    pub fn as_bytes(&self) -> &[u8] {
224        &self.bytes
225    }
226
227    /// Builds a `MultihashRef` corresponding to this `Multihash`.
228    pub fn as_ref(&self) -> MultihashRef<'_> {
229        MultihashRef { bytes: &self.bytes }
230    }
231
232    /// Returns which hashing algorithm is used in this multihash.
233    pub fn algorithm(&self) -> Hash {
234        self.as_ref().algorithm()
235    }
236
237    /// Returns the hashed data.
238    pub fn digest(&self) -> &[u8] {
239        self.as_ref().digest()
240    }
241}
242
243impl AsRef<[u8]> for Multihash {
244    fn as_ref(&self) -> &[u8] {
245        self.as_bytes()
246    }
247}
248
249impl Borrow<[u8]> for Multihash {
250    fn borrow(&self) -> &[u8] {
251        self.as_bytes()
252    }
253}
254
255impl<'a> PartialEq<MultihashRef<'a>> for Multihash {
256    fn eq(&self, other: &MultihashRef<'a>) -> bool {
257        &*self.bytes == other.bytes
258    }
259}
260
261impl TryFrom<Vec<u8>> for Multihash {
262    type Error = DecodeOwnedError;
263
264    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
265        Multihash::from_bytes(value)
266    }
267}
268
269/// Represents a valid multihash.
270#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
271pub struct MultihashRef<'a> { bytes: &'a [u8] }
272
273impl<'a> MultihashRef<'a> {
274    /// Creates a `MultihashRef` from the given `input`.
275    pub fn from_slice(input: &'a [u8]) -> Result<Self, DecodeError> {
276        if input.is_empty() {
277            return Err(DecodeError::BadInputLength);
278        }
279
280        // Ensure `Hash::code` returns a `u16` so that our `decode::u16` here is correct.
281        std::convert::identity::<fn(&'_ Hash) -> u16>(Hash::code);
282        let (code, bytes) = decode::u16(&input).map_err(|_| DecodeError::BadInputLength)?;
283
284        let alg = Hash::from_code(code).ok_or(DecodeError::UnknownCode)?;
285
286        // handle the identity case
287        if alg == Hash::Identity {
288            let (hash_len, bytes) = decode::u32(&bytes).map_err(|_| DecodeError::BadInputLength)?;
289            if as_u64(bytes.len()) != u64::from(hash_len) {
290                return Err(DecodeError::BadInputLength);
291            }
292            return Ok(MultihashRef { bytes: input });
293        }
294
295        let hash_len = usize::from(alg.size());
296
297        // Length of input after hash code should be exactly hash_len + 1
298        if bytes.len() != hash_len + 1 {
299            return Err(DecodeError::BadInputLength);
300        }
301
302        if usize::from(bytes[0]) != hash_len {
303            return Err(DecodeError::BadInputLength);
304        }
305
306        Ok(MultihashRef { bytes: input })
307    }
308
309    /// Returns which hashing algorithm is used in this multihash.
310    pub fn algorithm(&self) -> Hash {
311        let code = decode::u16(&self.bytes)
312            .expect("multihash is known to be valid algorithm")
313            .0;
314        Hash::from_code(code).expect("multihash is known to be valid")
315    }
316
317    /// Returns the hashed data.
318    pub fn digest(&self) -> &'a [u8] {
319        let bytes = decode::u16(&self.bytes)
320            .expect("multihash is known to be valid digest")
321            .1;
322        &bytes[1 ..]
323    }
324
325    /// Builds a `Multihash` that owns the data.
326    ///
327    /// This operation allocates.
328    pub fn into_owned(self) -> Multihash {
329        Multihash {
330            bytes: Bytes::copy_from_slice(self.bytes)
331        }
332    }
333
334    /// Returns the bytes representation of this multihash.
335    pub fn as_bytes(&self) -> &'a [u8] {
336        &self.bytes
337    }
338}
339
340impl<'a> PartialEq<Multihash> for MultihashRef<'a> {
341    fn eq(&self, other: &Multihash) -> bool {
342        self.bytes == &*other.bytes
343    }
344}
345
346#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
347fn as_u64(a: usize) -> u64 {
348    a as u64
349}
350
351/// Convert bytes to a hex representation
352pub fn to_hex(bytes: &[u8]) -> String {
353    let mut hex = String::with_capacity(bytes.len() * 2);
354
355    for byte in bytes {
356        write!(hex, "{:02x}", byte).expect("Can't fail on writing to string");
357    }
358
359    hex
360}
361
362#[cfg(test)]
363mod tests {
364    use crate::{Hash, Multihash};
365    use std::convert::TryFrom;
366
367    #[test]
368    fn rand_generates_valid_multihash() {
369        // Iterate over every possible hash function.
370        for code in 0 .. u16::max_value() {
371            let hash_fn = match Hash::from_code(code) {
372                Some(c) => c,
373                None => continue,
374            };
375
376            for _ in 0 .. 2000 {
377                let hash = Multihash::random(hash_fn);
378                assert_eq!(hash, Multihash::try_from(hash.to_vec()).unwrap());
379            }
380        }
381    }
382}