blot/multihash/
mod.rs

1// Copyright 2018 Arnau Siches
2//
3// Licensed under the MIT license <LICENSE or http://opensource.org/licenses/MIT>.
4// This file may not be copied, modified, or distributed except according to
5// those terms.
6
7//! Multihash implementation.
8//!
9//! This module defines the [`Multihash`] trait and the default hashing functions (digesters).
10
11use std::fmt;
12use tag::Tag;
13use uvar::Uvar;
14
15#[cfg(feature = "sha-1")]
16mod sha1;
17#[cfg(feature = "sha-1")]
18pub use self::sha1::Sha1;
19
20#[cfg(feature = "sha2")]
21mod sha2;
22#[cfg(feature = "sha2")]
23pub use self::sha2::{Sha2256, Sha2512};
24
25#[cfg(feature = "sha3")]
26mod sha3;
27#[cfg(feature = "sha3")]
28pub use self::sha3::{Sha3224, Sha3256, Sha3384, Sha3512};
29
30#[cfg(feature = "blake2")]
31mod blake2;
32#[cfg(feature = "blake2")]
33pub use self::blake2::{Blake2b512, Blake2s256};
34
35/// Multihash trait to be implemented by any algorithm used by Blot.
36///
37/// For example, the SHA3-512 algorithm:
38///
39/// ```
40/// use blot::multihash::{Sha3512, Multihash};
41/// use blot::uvar::Uvar;
42///
43/// let tag = Sha3512::default();
44///
45/// assert_eq!(tag.name(), "sha3-512");
46/// assert_eq!(tag.code(), Uvar::new(vec![0x14]));
47/// assert_eq!(tag.length(), 64);
48/// ```
49pub trait Multihash: Default + PartialEq {
50    type Digester: Default;
51
52    fn length(&self) -> u8;
53    fn code(&self) -> Uvar;
54    fn name(&self) -> &str;
55    fn digester(&self) -> Self::Digester {
56        Self::Digester::default()
57    }
58
59    fn digest_primitive(&self, tag: Tag, bytes: &[u8]) -> Harvest;
60    fn digest_collection(&self, tag: Tag, list: Vec<Vec<u8>>) -> Harvest;
61}
62
63#[derive(Debug)]
64pub enum MultihashError {
65    Unknown,
66}
67
68/// Multihash harvest digest.
69#[derive(Debug, PartialEq, Eq, Hash)]
70pub struct Harvest(Box<[u8]>);
71
72impl AsRef<[u8]> for Harvest {
73    fn as_ref(&self) -> &[u8] {
74        self.0.as_ref()
75    }
76}
77
78impl fmt::Display for Harvest {
79    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
80        for byte in self.0.as_ref() {
81            write!(formatter, "{:02x}", byte)?;
82        }
83
84        Ok(())
85    }
86}
87
88impl Harvest {
89    pub fn as_slice(&self) -> &[u8] {
90        &self.0
91    }
92}
93
94impl From<Vec<u8>> for Harvest {
95    fn from(vec: Vec<u8>) -> Self {
96        Harvest(vec.into_boxed_slice())
97    }
98}
99
100impl From<Box<[u8]>> for Harvest {
101    fn from(b: Box<[u8]>) -> Self {
102        Harvest(b)
103    }
104}
105
106/// Multihash tagged hash. Tags a harvested digest with a multihash implementation.
107#[derive(Debug, PartialEq, Eq, Hash)]
108pub struct Hash<T: Multihash> {
109    tag: T,
110    digest: Harvest,
111}
112
113impl<T: Multihash> Hash<T> {
114    pub fn new<D: Into<Harvest>>(tag: T, digest: D) -> Hash<T> {
115        Hash {
116            tag,
117            digest: digest.into(),
118        }
119    }
120
121    pub fn digest(&self) -> &Harvest {
122        &self.digest
123    }
124
125    pub fn tag(&self) -> &T {
126        &self.tag
127    }
128}
129
130impl<T: Multihash> fmt::Display for Hash<T> {
131    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
132        write!(formatter, "{:02x}", &self.tag.code())?;
133        write!(formatter, "{:02x}", &self.tag.length())?;
134        write!(formatter, "{}", &self.digest)?;
135
136        Ok(())
137    }
138}