1mod errors;
9mod hashes;
10
11use sha2::Digest;
12use std::{convert::TryFrom, fmt::Write};
13use unsigned_varint::{decode, encode};
14
15pub use self::errors::{DecodeError, DecodeOwnedError, EncodeError};
16pub use self::hashes::Hash;
17
18fn digest_encode<D: Digest>(input: &[u8], output: &mut [u8]) {
20 output.copy_from_slice(&D::digest(input))
21}
22
23macro_rules! match_encoder {
25 ($hash_id:ident for ($input:expr, $output:expr) {
26 $( $hashtype:ident => $hash_ty:path, )*
27 }) => ({
28 match $hash_id {
29 $(
30 Hash::$hashtype => digest_encode::<$hash_ty>($input, $output),
31 )*
32
33 _ => return Err(EncodeError::UnsupportedType)
34 }
35 })
36}
37
38pub fn encode(hash: Hash, input: &[u8]) -> Result<Multihash, EncodeError> {
58 let mut buf = encode::u16_buffer();
59 let code = encode::u16(hash.code(), &mut buf);
60
61 let header_len = code.len() + 1;
62 let size = hash.size();
63
64 let mut output = Vec::new();
65 output.resize(header_len + size as usize, 0);
66 output[..code.len()].copy_from_slice(code);
67 output[code.len()] = size;
68
69 match_encoder!(hash for (input, &mut output[header_len..]) {
70 SHA1 => sha1::Sha1,
71 SHA2256 => sha2::Sha256,
72 SHA2512 => sha2::Sha512,
73 SHA3224 => sha3::Sha3_224,
74 SHA3256 => sha3::Sha3_256,
75 SHA3384 => sha3::Sha3_384,
76 SHA3512 => sha3::Sha3_512,
77 Keccak224 => sha3::Keccak224,
78 Keccak256 => sha3::Keccak256,
79 Keccak384 => sha3::Keccak384,
80 Keccak512 => sha3::Keccak512,
81 Blake2b512 => blake2::Blake2b,
82 Blake2s256 => blake2::Blake2s,
83 });
84
85 Ok(Multihash { bytes: output })
86}
87
88#[derive(Debug, Clone, PartialEq, Eq, Hash)]
90pub struct Multihash {
91 bytes: Vec<u8>,
92}
93
94impl Multihash {
95 #[inline]
97 pub fn from_bytes(bytes: Vec<u8>) -> Result<Multihash, DecodeOwnedError> {
98 if let Err(err) = MultihashRef::from_slice(&bytes) {
99 return Err(DecodeOwnedError {
100 error: err,
101 data: bytes,
102 });
103 }
104
105 Ok(Multihash { bytes })
106 }
107
108 pub fn random(hash: Hash) -> Multihash {
110 let mut buf = encode::u16_buffer();
111 let code = encode::u16(hash.code(), &mut buf);
112
113 let header_len = code.len() + 1;
114 let size = hash.size();
115
116 let mut output = Vec::new();
117 output.resize(header_len + size as usize, 0);
118 output[..code.len()].copy_from_slice(code);
119 output[code.len()] = size;
120
121 for b in output[header_len..].iter_mut() {
122 *b = rand::random();
123 }
124
125 Multihash {
126 bytes: output,
127 }
128 }
129
130 #[inline]
132 pub fn into_bytes(self) -> Vec<u8> {
133 self.bytes
134 }
135
136 #[inline]
138 pub fn as_bytes(&self) -> &[u8] {
139 &self.bytes
140 }
141
142 #[inline]
144 pub fn as_ref(&self) -> MultihashRef<'_> {
145 MultihashRef { bytes: &self.bytes }
146 }
147
148 #[inline]
150 pub fn algorithm(&self) -> Hash {
151 self.as_ref().algorithm()
152 }
153
154 #[inline]
156 pub fn digest(&self) -> &[u8] {
157 self.as_ref().digest()
158 }
159}
160
161impl<'a> PartialEq<MultihashRef<'a>> for Multihash {
162 #[inline]
163 fn eq(&self, other: &MultihashRef<'a>) -> bool {
164 &*self.bytes == other.bytes
165 }
166}
167
168impl TryFrom<Vec<u8>> for Multihash {
169 type Error = DecodeOwnedError;
170
171 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
172 Multihash::from_bytes(value)
173 }
174}
175
176#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
178pub struct MultihashRef<'a> {
179 bytes: &'a [u8],
180}
181
182impl<'a> MultihashRef<'a> {
183 pub fn from_slice(input: &'a [u8]) -> Result<MultihashRef<'a>, DecodeError> {
185 if input.is_empty() {
186 return Err(DecodeError::BadInputLength);
187 }
188
189 let (code, bytes) = decode::u16(&input).map_err(|_| DecodeError::BadInputLength)?;
192
193 let alg = Hash::from_code(code).ok_or(DecodeError::UnknownCode)?;
194 let hash_len = alg.size() as usize;
195
196 if bytes.len() != hash_len + 1 {
198 return Err(DecodeError::BadInputLength);
199 }
200
201 if bytes[0] as usize != hash_len {
202 return Err(DecodeError::BadInputLength);
203 }
204
205 Ok(MultihashRef { bytes: input })
206 }
207
208 #[inline]
210 pub fn algorithm(&self) -> Hash {
211 let (code, _) = decode::u16(&self.bytes).expect("multihash is known to be valid algorithm");
212 Hash::from_code(code).expect("multihash is known to be valid")
213 }
214
215 #[inline]
217 pub fn digest(&self) -> &'a [u8] {
218 let (_, bytes) = decode::u16(&self.bytes).expect("multihash is known to be valid digest");
219 &bytes[1..]
220 }
221
222 #[inline]
226 pub fn into_owned(&self) -> Multihash {
227 Multihash {
228 bytes: self.bytes.to_owned(),
229 }
230 }
231
232 #[inline]
234 pub fn as_bytes(&self) -> &'a [u8] {
235 &self.bytes
236 }
237}
238
239impl<'a> PartialEq<Multihash> for MultihashRef<'a> {
240 #[inline]
241 fn eq(&self, other: &Multihash) -> bool {
242 self.bytes == &*other.bytes
243 }
244}
245
246pub fn to_hex(bytes: &[u8]) -> String {
248 let mut hex = String::with_capacity(bytes.len() * 2);
249
250 for byte in bytes {
251 write!(hex, "{:02x}", byte).expect("Can't fail on writing to string");
252 }
253
254 hex
255}
256
257#[cfg(test)]
258mod tests {
259 use crate::{Hash, Multihash};
260
261 #[test]
262 fn rand_generates_valid_multihash() {
263 for code in 0 .. u16::max_value() {
265 let hash_fn = match Hash::from_code(code) {
266 Some(c) => c,
267 None => continue,
268 };
269
270 for _ in 0 .. 2000 {
271 let hash = Multihash::random(hash_fn);
272 assert_eq!(hash, Multihash::from_bytes(hash.clone().into_bytes()).unwrap());
273 }
274 }
275 }
276}