1mod 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
22fn digest_encode<D: digest::Digest>(input: &[u8], output: &mut [u8]) {
24 output.copy_from_slice(&D::digest(input))
25}
26
27macro_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
42pub fn encode(hash: Hash, input: &[u8]) -> Result<Multihash, EncodeError> {
62 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
106fn 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#[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#[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
194pub struct Multihash { bytes: Bytes }
195
196impl Multihash {
197 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 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 pub fn into_bytes(self) -> Vec<u8> {
214 self.to_vec()
215 }
216
217 pub fn to_vec(&self) -> Vec<u8> {
219 Vec::from(&self.bytes[..])
220 }
221
222 pub fn as_bytes(&self) -> &[u8] {
224 &self.bytes
225 }
226
227 pub fn as_ref(&self) -> MultihashRef<'_> {
229 MultihashRef { bytes: &self.bytes }
230 }
231
232 pub fn algorithm(&self) -> Hash {
234 self.as_ref().algorithm()
235 }
236
237 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#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
271pub struct MultihashRef<'a> { bytes: &'a [u8] }
272
273impl<'a> MultihashRef<'a> {
274 pub fn from_slice(input: &'a [u8]) -> Result<Self, DecodeError> {
276 if input.is_empty() {
277 return Err(DecodeError::BadInputLength);
278 }
279
280 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 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 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 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 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 pub fn into_owned(self) -> Multihash {
329 Multihash {
330 bytes: Bytes::copy_from_slice(self.bytes)
331 }
332 }
333
334 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
351pub 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 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}