1use crate::{
2 hasher::Digest,
3 Error,
4};
5use core::{
6 convert::{
7 TryFrom,
8 TryInto,
9 },
10 fmt::Debug,
11};
12
13#[cfg(feature = "serde-codec")]
14use serde_big_array::BigArray;
15
16use bytecursor::ByteCursor;
17use alloc::vec::Vec;
18use unsigned_varint::{
19 decode,
20 encode as varint_encode,
21};
22
23pub trait MultihashDigest<const S: usize>:
30 TryFrom<u64> + Into<u64> + Send + Sync + Unpin + Copy + Eq + Debug + 'static {
31 fn digest(&self, input: &[u8]) -> Multihash<S>;
46
47 #[allow(clippy::needless_lifetimes)]
65 fn multihash_from_digest<'a, D, const DIGEST_SIZE: usize>(
66 digest: &'a D,
67 ) -> Multihash<S>
68 where
69 D: Digest<DIGEST_SIZE>,
70 Self: From<&'a D>;
71}
72
73#[cfg_attr(feature = "serde-codec", derive(serde::Deserialize))]
96#[cfg_attr(feature = "serde-codec", derive(serde::Serialize))]
97#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
98pub struct Multihash<const S: usize> {
99 code: u64,
101 size: u8,
103 #[cfg_attr(feature = "serde-codec", serde(with = "BigArray"))]
105 digest: [u8; S],
106}
107
108impl<const S: usize> Default for Multihash<S> {
109 fn default() -> Self { Self { code: 0, size: 0, digest: [0; S] } }
110}
111
112impl<const S: usize> Multihash<S> {
113 pub fn wrap(code: u64, input_digest: &[u8]) -> Result<Self, Error> {
115 if input_digest.len() > S {
116 return Err(Error::InvalidSize(input_digest.len() as _));
117 }
118 let size = input_digest.len();
119 let mut digest = [0; S];
120 digest[..size].copy_from_slice(input_digest);
121 Ok(Self { code, size: size as u8, digest })
122 }
123
124 pub fn code(&self) -> u64 { self.code }
126
127 pub fn size(&self) -> u8 { self.size }
129
130 pub fn digest(&self) -> &[u8] { &self.digest[..self.size as usize] }
132
133 pub fn read(r: &mut ByteCursor) -> Result<Self, Error>
135 where Self: Sized {
136 let (code, size, digest) = match read_multihash(r) {
137 Ok((c, s, d)) => (c, s, d),
138 Err(e) => return Err(e),
139 };
140 Ok(Self { code, size, digest })
141 }
142
143 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error>
148 where Self: Sized {
149 let mut r = ByteCursor::new(bytes.to_vec());
150 let result = match Self::read(&mut r) {
151 Ok(r) => r,
152 Err(_) => return Err(Error::Varint(decode::Error::Overflow)),
153 };
154 if bytes.len() >= r.position() as usize + 1 {
156 return Err(Error::InvalidSize(r.get_ref().len().try_into().expect(
157 "Currently the maximum size is 255, therefore always fits into usize",
158 )));
159 }
160
161 Ok(result)
162 }
163
164 pub fn write(&self, w: &mut ByteCursor) -> Result<(), Error> {
166 write_multihash(w, self.code(), self.size(), self.digest())
167 }
168
169 pub fn to_bytes(&self) -> Vec<u8> {
171 let mut bytes = ByteCursor::new(Vec::with_capacity(self.size().into()));
172 self.write(&mut bytes).expect("writing to a vec should never fail");
173
174 bytes.into_inner()
175 }
176}
177
178#[allow(clippy::derive_hash_xor_eq)]
180impl<const S: usize> core::hash::Hash for Multihash<S> {
181 fn hash<T: core::hash::Hasher>(&self, state: &mut T) {
182 self.code.hash(state);
183 self.digest().hash(state);
184 }
185}
186
187impl<const S: usize> From<Multihash<S>> for Vec<u8> {
188 fn from(multihash: Multihash<S>) -> Self { multihash.to_bytes() }
189}
190
191#[cfg(feature = "scale-codec")]
192impl<const S: usize> parity_scale_codec::Encode for Multihash<S> {
193 fn encode_to<EncOut: parity_scale_codec::Output + ?Sized>(
194 &self,
195 dest: &mut EncOut,
196 ) {
197 self.code.encode_to(dest);
198 self.size.encode_to(dest);
199 dest.write(self.digest());
200 }
201}
202
203#[cfg(feature = "scale-codec")]
204impl<const S: usize> parity_scale_codec::EncodeLike for Multihash<S> {}
205
206#[cfg(feature = "scale-codec")]
207impl<const S: usize> parity_scale_codec::Decode for Multihash<S> {
208 fn decode<DecIn: parity_scale_codec::Input>(
209 input: &mut DecIn,
210 ) -> Result<Self, parity_scale_codec::Error> {
211 let mut mh = Multihash {
212 code: parity_scale_codec::Decode::decode(input)?,
213 size: parity_scale_codec::Decode::decode(input)?,
214 digest: [0; S],
215 };
216 if mh.size as usize > S {
217 Err(parity_scale_codec::Error::from("invalid size"))
218 } else {
219 input.read(&mut mh.digest[..mh.size as usize])?;
220 Ok(mh)
221 }
222 }
223}
224
225pub fn write_multihash(
227 w: &mut ByteCursor,
228 code: u64,
229 size: u8,
230 digest: &[u8],
231) -> Result<(), Error> {
232 let mut code_buf = varint_encode::u64_buffer();
233 let code = varint_encode::u64(code, &mut code_buf);
234
235 let mut size_buf = varint_encode::u8_buffer();
236 let size = varint_encode::u8(size, &mut size_buf);
237
238 match w.write_all(code) {
239 Ok(_) => (),
240 Err(_) => return Err(Error::Varint(decode::Error::Overflow)),
241 };
242 match w.write_all(size) {
243 Ok(_) => (),
244 Err(_) => return Err(Error::Varint(decode::Error::Overflow)),
245 };
246 match w.write_all(digest) {
247 Ok(_) => (),
248 Err(_) => return Err(Error::Varint(decode::Error::Overflow)),
249 };
250 w.set_position(0);
251 Ok(())
252}
253
254pub fn read_u64(r: &mut ByteCursor) -> Result<u64, Error> {
258 let mut b = varint_encode::u64_buffer();
259 for i in 0..b.len() {
260 let n = r.read(&mut b[i..(i + 1)]);
261 if n == 0 {
262 return Err(Error::Varint(decode::Error::Overflow));
263 }
264 if decode::is_last(b[i]) {
265 match decode::u64(&b[..=i]) {
266 Ok(d) => return Ok(d.0),
267 Err(_) => return Err(Error::Varint(decode::Error::Overflow)),
268 };
269 }
271 }
272 Err(Error::Varint(decode::Error::Overflow))
273}
274
275pub fn read_multihash<const S: usize>(
283 r: &mut ByteCursor,
284) -> Result<(u64, u8, [u8; S]), Error> {
285 let code = match read_u64(r) {
286 Ok(c) => c,
287 Err(e) => return Err(e),
288 };
289 let size = match read_u64(r) {
290 Ok(s) => s,
291 Err(e) => return Err(e),
292 };
293
294 if size > S.try_into().unwrap() || size > u8::MAX as u64 {
295 return Err(Error::InvalidSize(size));
296 }
297
298 let mut digest = [0; S];
299
300 match r.read_exact(&mut digest[..size as usize]) {
301 Ok(_) => (),
302 Err(_) => return Err(Error::Varint(decode::Error::Overflow)),
303 }
304 Ok((code, size as u8, digest))
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310 use crate::multihash_impl::Code;
311
312 #[test]
313 fn roundtrip() {
314 let hash = Code::Sha2_256.digest(b"hello world");
315 let mut buf = ByteCursor::new([0u8; 35].to_vec());
316 hash.write(&mut buf).unwrap();
317 buf.set_position(0);
318 let hash2 = Multihash::read(&mut buf).unwrap();
319 assert_eq!(hash, hash2);
320 }
321
322 #[test]
323 #[cfg(feature = "scale-codec")]
324 fn test_scale() {
325 use crate::{Hasher, Sha2_256};
326 use parity_scale_codec::{
327 Decode,
328 Encode,
329 };
330
331 let mh1 = Multihash::<32>::wrap(
332 Code::Sha2_256.into(),
333 Sha2_256::digest(b"hello world").as_ref(),
334 )
335 .unwrap();
336 let mh1_bytes = mh1.encode();
338 let mh2: Multihash<32> = Decode::decode(&mut &mh1_bytes[..]).unwrap();
340 assert_eq!(mh1, mh2);
341
342 let mh3: Multihash<64> = Code::Sha2_256.digest(b"hello world");
343 let mh3_bytes = mh3.encode();
345 let mh4: Multihash<64> = Decode::decode(&mut &mh3_bytes[..]).unwrap();
347 assert_eq!(mh3, mh4);
348
349 assert_eq!(mh1_bytes, mh3_bytes);
350 }
351
352 #[test]
353 #[cfg(feature = "serde-codec")]
354 fn test_serde() {
355 let mh = Multihash::<32>::default();
356 let bytes = serde_json::to_string(&mh).unwrap();
357 let mh2 = serde_json::from_str(&bytes).unwrap();
358 assert_eq!(mh, mh2);
359 }
360}