1pub mod prelude {
11 pub use super::MultihashCode;
12 pub use multihash_codetable::MultihashDigest as _;
13}
14
15use multihash_derive::{Hasher, MultihashDigest};
16
17#[derive(Clone, Copy, Debug, Eq, MultihashDigest, PartialEq)]
21#[mh(alloc_size = 64)]
22pub enum MultihashCode {
23 #[mh(code = 0x0, hasher = IdentityHasher::<64>)]
24 Identity,
25 #[mh(code = 0x12, hasher = multihash_codetable::Sha2_256)]
27 Sha2_256,
28 #[mh(code = 0x13, hasher = multihash_codetable::Sha2_512)]
30 Sha2_512,
31 #[mh(code = 0x17, hasher = multihash_codetable::Sha3_224)]
33 Sha3_224,
34 #[mh(code = 0x16, hasher = multihash_codetable::Sha3_256)]
36 Sha3_256,
37 #[mh(code = 0x15, hasher = multihash_codetable::Sha3_384)]
39 Sha3_384,
40 #[mh(code = 0x14, hasher = multihash_codetable::Sha3_512)]
42 Sha3_512,
43 #[mh(code = 0x1a, hasher = multihash_codetable::Keccak224)]
45 Keccak224,
46 #[mh(code = 0x1b, hasher = multihash_codetable::Keccak256)]
48 Keccak256,
49 #[mh(code = 0x1c, hasher = multihash_codetable::Keccak384)]
51 Keccak384,
52 #[mh(code = 0x1d, hasher = multihash_codetable::Keccak512)]
54 Keccak512,
55 #[mh(code = 0xb220, hasher = multihash_codetable::Blake2b256)]
57 Blake2b256,
58 #[mh(code = 0xb240, hasher = multihash_codetable::Blake2b512)]
60 Blake2b512,
61 #[mh(code = 0xb250, hasher = multihash_codetable::Blake2s128)]
63 Blake2s128,
64 #[mh(code = 0xb260, hasher = multihash_codetable::Blake2s256)]
66 Blake2s256,
67 #[mh(code = 0x1e, hasher = multihash_codetable::Blake3_256)]
69 Blake3_256,
70 #[mh(code = 0x1053, hasher = multihash_codetable::Ripemd160)]
72 Ripemd160,
73 #[mh(code = 0x1054, hasher = multihash_codetable::Ripemd256)]
75 Ripemd256,
76 #[mh(code = 0x1055, hasher = multihash_codetable::Ripemd320)]
78 Ripemd320,
79}
80
81impl MultihashCode {
82 pub const IDENTITY_MAX_SIZE: usize = 64;
85
86 pub fn checked_digest(&self, data: &[u8]) -> anyhow::Result<Multihash> {
89 anyhow::ensure!(
90 *self != Self::Identity || data.len() <= Self::IDENTITY_MAX_SIZE,
91 "identity multihash input of {} bytes exceeds the {}-byte limit",
92 data.len(),
93 Self::IDENTITY_MAX_SIZE
94 );
95 Ok(self.digest(data))
96 }
97
98 pub fn digest_byte_stream<R: std::io::Read>(&self, bytes: &mut R) -> anyhow::Result<Multihash> {
100 fn hash<'a, H: Hasher, R: std::io::Read>(
101 hasher: &'a mut H,
102 bytes: &'a mut R,
103 ) -> anyhow::Result<&'a [u8]> {
104 let mut buf = [0; 1024];
105 loop {
106 let n = bytes.read(&mut buf)?;
107 if n == 0 {
108 break;
109 }
110 if let Some(b) = buf.get(0..n) {
111 hasher.update(b);
112 }
113 }
114 Ok(hasher.finalize())
115 }
116
117 Ok(match self {
118 Self::Sha2_256 => {
119 let mut hasher = multihash_codetable::Sha2_256::default();
120 self.wrap(hash(&mut hasher, bytes)?)?
121 }
122 Self::Sha2_512 => {
123 let mut hasher = multihash_codetable::Sha2_512::default();
124 self.wrap(hash(&mut hasher, bytes)?)?
125 }
126 Self::Sha3_224 => {
127 let mut hasher = multihash_codetable::Sha3_224::default();
128 self.wrap(hash(&mut hasher, bytes)?)?
129 }
130 Self::Sha3_256 => {
131 let mut hasher = multihash_codetable::Sha3_256::default();
132 self.wrap(hash(&mut hasher, bytes)?)?
133 }
134 Self::Sha3_384 => {
135 let mut hasher = multihash_codetable::Sha3_384::default();
136 self.wrap(hash(&mut hasher, bytes)?)?
137 }
138 Self::Sha3_512 => {
139 let mut hasher = multihash_codetable::Sha3_512::default();
140 self.wrap(hash(&mut hasher, bytes)?)?
141 }
142 Self::Keccak224 => {
143 let mut hasher = multihash_codetable::Keccak224::default();
144 self.wrap(hash(&mut hasher, bytes)?)?
145 }
146 Self::Keccak256 => {
147 let mut hasher = multihash_codetable::Keccak256::default();
148 self.wrap(hash(&mut hasher, bytes)?)?
149 }
150 Self::Keccak384 => {
151 let mut hasher = multihash_codetable::Keccak384::default();
152 self.wrap(hash(&mut hasher, bytes)?)?
153 }
154 Self::Keccak512 => {
155 let mut hasher = multihash_codetable::Keccak512::default();
156 self.wrap(hash(&mut hasher, bytes)?)?
157 }
158 Self::Blake2b256 => {
159 let mut hasher = multihash_codetable::Blake2b256::default();
160 self.wrap(hash(&mut hasher, bytes)?)?
161 }
162 Self::Blake2b512 => {
163 let mut hasher = multihash_codetable::Blake2b512::default();
164 self.wrap(hash(&mut hasher, bytes)?)?
165 }
166 Self::Blake2s128 => {
167 let mut hasher = multihash_codetable::Blake2s128::default();
168 self.wrap(hash(&mut hasher, bytes)?)?
169 }
170 Self::Blake2s256 => {
171 let mut hasher = multihash_codetable::Blake2s256::default();
172 self.wrap(hash(&mut hasher, bytes)?)?
173 }
174 Self::Blake3_256 => {
175 let mut hasher = multihash_codetable::Blake3_256::default();
176 self.wrap(hash(&mut hasher, bytes)?)?
177 }
178 Self::Ripemd160 => {
179 let mut hasher = multihash_codetable::Ripemd160::default();
180 self.wrap(hash(&mut hasher, bytes)?)?
181 }
182 Self::Ripemd256 => {
183 let mut hasher = multihash_codetable::Ripemd256::default();
184 self.wrap(hash(&mut hasher, bytes)?)?
185 }
186 Self::Ripemd320 => {
187 let mut hasher = multihash_codetable::Ripemd320::default();
188 self.wrap(hash(&mut hasher, bytes)?)?
189 }
190 _ => {
191 anyhow::bail!("`digest_byte_stream` is unimplemented for {self:?}");
192 }
193 })
194 }
195}
196
197#[derive(Debug)]
204pub struct IdentityHasher<const S: usize> {
205 i: usize,
206 bytes: [u8; S],
207}
208
209impl<const S: usize> Default for IdentityHasher<S> {
210 fn default() -> Self {
211 Self {
212 i: 0,
213 bytes: [0u8; S],
214 }
215 }
216}
217
218impl<const S: usize> multihash_derive::Hasher for IdentityHasher<S> {
219 fn update(&mut self, input: &[u8]) {
220 let start = self.i.min(self.bytes.len());
221 let end = (self.i + input.len()).min(self.bytes.len());
222 self.bytes[start..end].copy_from_slice(input);
223 self.i = end;
224 }
225
226 fn finalize(&mut self) -> &[u8] {
227 &self.bytes[..self.i]
228 }
229
230 fn reset(&mut self) {
231 self.i = 0
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use std::io::Cursor;
238
239 use super::*;
240 use crate::utils::rand::forest_rng;
241 use quickcheck_macros::quickcheck;
242 use rand::RngCore as _;
243
244 #[quickcheck]
245 fn checked_digest_bounds(data: Vec<u8>) -> bool {
246 use MultihashCode::*;
247 let ok_sha = Sha2_256.checked_digest(&data).is_ok();
248 let ok_identity = Identity.checked_digest(&data).is_ok()
249 == (data.len() <= MultihashCode::IDENTITY_MAX_SIZE);
250 ok_sha && ok_identity
251 }
252
253 #[test]
254 fn test_digest_byte_stream() {
255 use MultihashCode::*;
256
257 for len in [0, 1, 100, 1024, 10000] {
258 let mut bytes = vec![0; len];
259 forest_rng().fill_bytes(&mut bytes);
260 let mut cursor = Cursor::new(bytes.clone());
261 for code in [
262 Sha2_256, Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512, Keccak224, Keccak256,
263 Keccak384, Keccak512, Blake2b256, Blake2b512, Blake2s128, Blake2s256, Blake3_256,
264 Ripemd160, Ripemd256, Ripemd320,
265 ] {
266 cursor.set_position(0);
267 let mh1 = code.digest(&bytes);
268 let mh2 = code.digest_byte_stream(&mut cursor).unwrap();
269 assert_eq!(mh1, mh2);
270 }
271
272 cursor.set_position(0);
273 Identity.digest_byte_stream(&mut cursor).unwrap_err();
274 }
275 }
276}