/__w/smoldot/smoldot/repo/lib/src/libp2p/multihash.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Smoldot |
2 | | // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. |
3 | | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 |
4 | | |
5 | | // This program is free software: you can redistribute it and/or modify |
6 | | // it under the terms of the GNU General Public License as published by |
7 | | // the Free Software Foundation, either version 3 of the License, or |
8 | | // (at your option) any later version. |
9 | | |
10 | | // This program is distributed in the hope that it will be useful, |
11 | | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | // GNU General Public License for more details. |
14 | | |
15 | | // You should have received a copy of the GNU General Public License |
16 | | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | | |
18 | | //! A multihash is a small data structure containing a code (an integer) and data. The format of |
19 | | //! the data depends on the code. |
20 | | //! |
21 | | //! See <https://github.com/multiformats/multihash> |
22 | | |
23 | | use alloc::vec::Vec; |
24 | | use core::fmt; |
25 | | |
26 | | use crate::util; |
27 | | |
28 | | /// A multihash made of a code and a slice of data. |
29 | | /// |
30 | | /// This type contains a generic parameter `T` that stores the multihash itself, for example |
31 | | /// `Vec<u8>` or `&[u8]`. |
32 | | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
33 | | pub struct Multihash<T = Vec<u8>>(T); |
34 | | |
35 | | impl<T: AsRef<[u8]>> Multihash<T> { |
36 | | /// Returns the code stored in this multihash. |
37 | 2 | pub fn hash_algorithm_code(&self) -> u32 { |
38 | 2 | decode(&self.0.as_ref()).unwrap().0 |
39 | 2 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE19hash_algorithm_codeB6_ Line | Count | Source | 37 | 2 | pub fn hash_algorithm_code(&self) -> u32 { | 38 | 2 | decode(&self.0.as_ref()).unwrap().0 | 39 | 2 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE19hash_algorithm_codeCsih6EgvAwZF2_13smoldot_light Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE19hash_algorithm_codeB6_ |
40 | | |
41 | | /// Returns the data stored in this multihash. |
42 | 2 | pub fn data(&self) -> &[u8] { |
43 | 2 | decode(&self.0.as_ref()).unwrap().1 |
44 | 2 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE4dataB6_ Line | Count | Source | 42 | 2 | pub fn data(&self) -> &[u8] { | 43 | 2 | decode(&self.0.as_ref()).unwrap().1 | 44 | 2 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE4dataB6_ |
45 | | |
46 | | /// Checks whether `input` is a valid multihash. |
47 | 11 | pub fn from_bytes(input: T) -> Result<Self, (FromBytesError, T)> { |
48 | 11 | if let Err(err0 ) = decode(input.as_ref()) { |
49 | 0 | return Err((err, input)); |
50 | 11 | } |
51 | 11 | |
52 | 11 | Ok(Multihash(input)) |
53 | 11 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashINtNtCsdZExvAaxgia_5alloc6borrow3CowShEE10from_bytesB6_ Line | Count | Source | 47 | 3 | pub fn from_bytes(input: T) -> Result<Self, (FromBytesError, T)> { | 48 | 3 | if let Err(err0 ) = decode(input.as_ref()) { | 49 | 0 | return Err((err, input)); | 50 | 3 | } | 51 | 3 | | 52 | 3 | Ok(Multihash(input)) | 53 | 3 | } |
_RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE10from_bytesB6_ Line | Count | Source | 47 | 2 | pub fn from_bytes(input: T) -> Result<Self, (FromBytesError, T)> { | 48 | 2 | if let Err(err0 ) = decode(input.as_ref()) { | 49 | 0 | return Err((err, input)); | 50 | 2 | } | 51 | 2 | | 52 | 2 | Ok(Multihash(input)) | 53 | 2 | } |
_RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesB6_ Line | Count | Source | 47 | 6 | pub fn from_bytes(input: T) -> Result<Self, (FromBytesError, T)> { | 48 | 6 | if let Err(err0 ) = decode(input.as_ref()) { | 49 | 0 | return Err((err, input)); | 50 | 6 | } | 51 | 6 | | 52 | 6 | Ok(Multihash(input)) | 53 | 6 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCsih6EgvAwZF2_13smoldot_light Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashINtNtCsdZExvAaxgia_5alloc6borrow3CowShEE10from_bytesB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE10from_bytesB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCsibGXYHQB8Ea_25json_rpc_general_requests |
54 | | |
55 | | /// Destroys the [`Multihash`] and returns the underlying buffer. |
56 | 176 | pub fn into_bytes(self) -> T { |
57 | 176 | self.0 |
58 | 176 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashNtB2_9Multihash10into_bytesB6_ Line | Count | Source | 56 | 28 | pub fn into_bytes(self) -> T { | 57 | 28 | self.0 | 58 | 28 | } |
_RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashRShE10into_bytesB6_ Line | Count | Source | 56 | 2 | pub fn into_bytes(self) -> T { | 57 | 2 | self.0 | 58 | 2 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10into_bytesCsDDUKWWCHAU_18smoldot_light_wasm _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashNtB2_9Multihash10into_bytesB6_ Line | Count | Source | 56 | 146 | pub fn into_bytes(self) -> T { | 57 | 146 | self.0 | 58 | 146 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10into_bytesCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10into_bytesCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10into_bytesCsibGXYHQB8Ea_25json_rpc_general_requests |
59 | | } |
60 | | |
61 | | impl<'a> Multihash<&'a [u8]> { |
62 | | /// Returns the data stored in this multihash. |
63 | 0 | pub fn data_ref(&self) -> &'a [u8] { |
64 | 0 | decode(&self.0.as_ref()).unwrap().1 |
65 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB4_9MultihashRShE8data_ref Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB4_9MultihashRShE8data_ref |
66 | | |
67 | | /// Checks whether `input` is a valid multihash. |
68 | | /// |
69 | | /// Contrary to [`Multihash::from_bytes`], doesn't return an error if the slice is too long |
70 | | /// but returns the remainder. |
71 | 0 | pub fn from_bytes_partial( |
72 | 0 | input: &'a [u8], |
73 | 0 | ) -> Result<(Multihash<&'a [u8]>, &'a [u8]), FromBytesError> { |
74 | 0 | match multihash::<nom::error::Error<&[u8]>>(input) { |
75 | 0 | Ok((rest, _)) => Ok((Multihash(&input.as_ref()[..rest.len()]), rest)), |
76 | 0 | Err(_) => Err(FromBytesError::DecodeError), |
77 | | } |
78 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB4_9MultihashRShE18from_bytes_partial Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB4_9MultihashRShE18from_bytes_partial |
79 | | } |
80 | | |
81 | | impl Multihash<Vec<u8>> { |
82 | | /// Builds a multihash from the "identity" hash algorithm code and the provided data. |
83 | | /// |
84 | | /// Calling [`Multihash::data`] on the returned value will always yield back the same data |
85 | | /// as was passed as parameter. |
86 | 174 | pub fn identity<'a>(data: &'a [u8]) -> Self { |
87 | 174 | let mut out = Vec::with_capacity(data.len() + 8); |
88 | 174 | out.extend(util::leb128::encode(0u32)); |
89 | 174 | out.extend(util::leb128::encode_usize(data.len())); |
90 | 174 | out.extend_from_slice(data); |
91 | 174 | Multihash(out) |
92 | 174 | } _RNvMs0_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashNtB5_9Multihash8identity Line | Count | Source | 86 | 28 | pub fn identity<'a>(data: &'a [u8]) -> Self { | 87 | 28 | let mut out = Vec::with_capacity(data.len() + 8); | 88 | 28 | out.extend(util::leb128::encode(0u32)); | 89 | 28 | out.extend(util::leb128::encode_usize(data.len())); | 90 | 28 | out.extend_from_slice(data); | 91 | 28 | Multihash(out) | 92 | 28 | } |
_RNvMs0_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashNtB5_9Multihash8identity Line | Count | Source | 86 | 146 | pub fn identity<'a>(data: &'a [u8]) -> Self { | 87 | 146 | let mut out = Vec::with_capacity(data.len() + 8); | 88 | 146 | out.extend(util::leb128::encode(0u32)); | 89 | 146 | out.extend(util::leb128::encode_usize(data.len())); | 90 | 146 | out.extend_from_slice(data); | 91 | 146 | Multihash(out) | 92 | 146 | } |
|
93 | | } |
94 | | |
95 | | impl<T> AsRef<T> for Multihash<T> { |
96 | 4 | fn as_ref(&self) -> &T { |
97 | 4 | &self.0 |
98 | 4 | } _RNvXs1_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB5_9MultihashINtNtCsdZExvAaxgia_5alloc6borrow3CowShEEINtNtCsaYZPK01V26L_4core7convert5AsRefB11_E6as_refB9_ Line | Count | Source | 96 | 3 | fn as_ref(&self) -> &T { | 97 | 3 | &self.0 | 98 | 3 | } |
_RNvXs1_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB11_E6as_refB9_ Line | Count | Source | 96 | 1 | fn as_ref(&self) -> &T { | 97 | 1 | &self.0 | 98 | 1 | } |
Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashINtNtCsdZExvAaxgia_5alloc6borrow3CowShEEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refB9_ Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashNtB5_9MultihashINtNtCsaYZPK01V26L_4core7convert5AsRefINtNtCsdZExvAaxgia_5alloc3vec3VechEE6as_refB9_ Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refCsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refCscDgN54JpMGG_6author Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refCsibGXYHQB8Ea_25json_rpc_general_requests |
99 | | } |
100 | | |
101 | | /// Error when turning bytes into a [`Multihash`]. |
102 | 0 | #[derive(Debug, derive_more::Display, Clone)] Unexecuted instantiation: _RNvXsc_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashNtB5_14FromBytesErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsc_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashNtB5_14FromBytesErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
103 | | pub enum FromBytesError { |
104 | | /// The multihash is invalid. |
105 | | DecodeError, |
106 | | } |
107 | | |
108 | | impl<T: AsRef<[u8]>> fmt::Debug for Multihash<T> { |
109 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
110 | 0 | fmt::Display::fmt(self, f) |
111 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashs2_0pEINtB5_9MultihashpENtNtCsaYZPK01V26L_4core3fmt5Debug3fmtB9_ Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot6libp2p9multihashs2_0pEINtB5_9MultihashpENtNtCsaYZPK01V26L_4core3fmt5Debug3fmtB9_ |
112 | | } |
113 | | |
114 | | impl<T: AsRef<[u8]>> fmt::Display for Multihash<T> { |
115 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
116 | 0 | let base58 = bs58::encode(self.0.as_ref()).into_string(); |
117 | 0 | write!(f, "{base58}") |
118 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashs3_0pEINtB5_9MultihashpENtNtCsaYZPK01V26L_4core3fmt7Display3fmtB9_ Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot6libp2p9multihashs3_0pEINtB5_9MultihashpENtNtCsaYZPK01V26L_4core3fmt7Display3fmtB9_ |
119 | | } |
120 | | |
121 | 15 | fn decode<'a>(bytes: &'a [u8]) -> Result<(u32, &'a [u8]), FromBytesError> { |
122 | 15 | match nom::combinator::all_consuming(multihash::<nom::error::Error<&[u8]>>)(bytes) { |
123 | 15 | Ok((_rest, multihash)) => { |
124 | 15 | debug_assert!(_rest.is_empty()); |
125 | 15 | Ok(multihash) |
126 | | } |
127 | 0 | Err(_) => Err(FromBytesError::DecodeError), |
128 | | } |
129 | 15 | } _RNvNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihash6decode Line | Count | Source | 121 | 15 | fn decode<'a>(bytes: &'a [u8]) -> Result<(u32, &'a [u8]), FromBytesError> { | 122 | 15 | match nom::combinator::all_consuming(multihash::<nom::error::Error<&[u8]>>)(bytes) { | 123 | 15 | Ok((_rest, multihash)) => { | 124 | 15 | debug_assert!(_rest.is_empty()); | 125 | 15 | Ok(multihash) | 126 | | } | 127 | 0 | Err(_) => Err(FromBytesError::DecodeError), | 128 | | } | 129 | 15 | } |
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6libp2p9multihash6decode |
130 | | |
131 | 15 | fn multihash<'a, E: nom::error::ParseError<&'a [u8]>>( |
132 | 15 | bytes: &'a [u8], |
133 | 15 | ) -> nom::IResult<&'a [u8], (u32, &'a [u8]), E> { |
134 | 15 | nom::sequence::tuple(( |
135 | 15 | nom::combinator::map_opt(crate::util::leb128::nom_leb128_usize, |c| { |
136 | 15 | u32::try_from(c).ok() |
137 | 15 | }), _RNCINvNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihash9multihashINtNtCs6ga8gEqbpRc_3nom5error5ErrorRShEE0B8_ Line | Count | Source | 135 | 15 | nom::combinator::map_opt(crate::util::leb128::nom_leb128_usize, |c| { | 136 | 15 | u32::try_from(c).ok() | 137 | 15 | }), |
Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6libp2p9multihash9multihashINtNtCs6ga8gEqbpRc_3nom5error5ErrorRShEE0B8_ |
138 | 15 | nom::multi::length_data(crate::util::leb128::nom_leb128_usize), |
139 | 15 | ))(bytes) |
140 | 15 | } _RINvNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihash9multihashINtNtCs6ga8gEqbpRc_3nom5error5ErrorRShEEB6_ Line | Count | Source | 131 | 15 | fn multihash<'a, E: nom::error::ParseError<&'a [u8]>>( | 132 | 15 | bytes: &'a [u8], | 133 | 15 | ) -> nom::IResult<&'a [u8], (u32, &'a [u8]), E> { | 134 | 15 | nom::sequence::tuple(( | 135 | 15 | nom::combinator::map_opt(crate::util::leb128::nom_leb128_usize, |c| { | 136 | | u32::try_from(c).ok() | 137 | 15 | }), | 138 | 15 | nom::multi::length_data(crate::util::leb128::nom_leb128_usize), | 139 | 15 | ))(bytes) | 140 | 15 | } |
Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot6libp2p9multihash9multihashINtNtCs6ga8gEqbpRc_3nom5error5ErrorRShEEB6_ |