Skip to main content

forest/utils/
multihash.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4//!
5//! This module back-fills the Identify hasher and code that was removed in `multihash` crate.
6//! See <https://github.com/multiformats/rust-multihash/blob/master/CHANGELOG.md#-breaking-changes>
7//! and <https://github.com/multiformats/rust-multihash/pull/289>
8//!
9
10pub mod prelude {
11    pub use super::MultihashCode;
12    pub use multihash_codetable::MultihashDigest as _;
13}
14
15use multihash_derive::{Hasher, MultihashDigest};
16
17/// Extends [`multihash_codetable::Code`] with `Identity`
18#[derive(Clone, Copy, Debug, Eq, MultihashDigest, PartialEq)]
19#[mh(alloc_size = 64)]
20pub enum MultihashCode {
21    #[mh(code = 0x0, hasher = IdentityHasher::<64>)]
22    Identity,
23    /// SHA-256 (32-byte hash size)
24    #[mh(code = 0x12, hasher = multihash_codetable::Sha2_256)]
25    Sha2_256,
26    /// SHA-512 (64-byte hash size)
27    #[mh(code = 0x13, hasher = multihash_codetable::Sha2_512)]
28    Sha2_512,
29    /// SHA3-224 (28-byte hash size)
30    #[mh(code = 0x17, hasher = multihash_codetable::Sha3_224)]
31    Sha3_224,
32    /// SHA3-256 (32-byte hash size)
33    #[mh(code = 0x16, hasher = multihash_codetable::Sha3_256)]
34    Sha3_256,
35    /// SHA3-384 (48-byte hash size)
36    #[mh(code = 0x15, hasher = multihash_codetable::Sha3_384)]
37    Sha3_384,
38    /// SHA3-512 (64-byte hash size)
39    #[mh(code = 0x14, hasher = multihash_codetable::Sha3_512)]
40    Sha3_512,
41    /// Keccak-224 (28-byte hash size)
42    #[mh(code = 0x1a, hasher = multihash_codetable::Keccak224)]
43    Keccak224,
44    /// Keccak-256 (32-byte hash size)
45    #[mh(code = 0x1b, hasher = multihash_codetable::Keccak256)]
46    Keccak256,
47    /// Keccak-384 (48-byte hash size)
48    #[mh(code = 0x1c, hasher = multihash_codetable::Keccak384)]
49    Keccak384,
50    /// Keccak-512 (64-byte hash size)
51    #[mh(code = 0x1d, hasher = multihash_codetable::Keccak512)]
52    Keccak512,
53    /// BLAKE2b-256 (32-byte hash size)
54    #[mh(code = 0xb220, hasher = multihash_codetable::Blake2b256)]
55    Blake2b256,
56    /// BLAKE2b-512 (64-byte hash size)
57    #[mh(code = 0xb240, hasher = multihash_codetable::Blake2b512)]
58    Blake2b512,
59    /// BLAKE2s-128 (16-byte hash size)
60    #[mh(code = 0xb250, hasher = multihash_codetable::Blake2s128)]
61    Blake2s128,
62    /// BLAKE2s-256 (32-byte hash size)
63    #[mh(code = 0xb260, hasher = multihash_codetable::Blake2s256)]
64    Blake2s256,
65    /// BLAKE3-256 (32-byte hash size)
66    #[mh(code = 0x1e, hasher = multihash_codetable::Blake3_256)]
67    Blake3_256,
68    /// RIPEMD-160 (20-byte hash size)
69    #[mh(code = 0x1053, hasher = multihash_codetable::Ripemd160)]
70    Ripemd160,
71    /// RIPEMD-256 (32-byte hash size)
72    #[mh(code = 0x1054, hasher = multihash_codetable::Ripemd256)]
73    Ripemd256,
74    /// RIPEMD-320 (40-byte hash size)
75    #[mh(code = 0x1055, hasher = multihash_codetable::Ripemd320)]
76    Ripemd320,
77}
78
79impl MultihashCode {
80    /// Calculate the [`Multihash`] of the input byte stream.
81    pub fn digest_byte_stream<R: std::io::Read>(&self, bytes: &mut R) -> anyhow::Result<Multihash> {
82        fn hash<'a, H: Hasher, R: std::io::Read>(
83            hasher: &'a mut H,
84            bytes: &'a mut R,
85        ) -> anyhow::Result<&'a [u8]> {
86            let mut buf = [0; 1024];
87            loop {
88                let n = bytes.read(&mut buf)?;
89                if n == 0 {
90                    break;
91                }
92                if let Some(b) = buf.get(0..n) {
93                    hasher.update(b);
94                }
95            }
96            Ok(hasher.finalize())
97        }
98
99        Ok(match self {
100            Self::Sha2_256 => {
101                let mut hasher = multihash_codetable::Sha2_256::default();
102                self.wrap(hash(&mut hasher, bytes)?)?
103            }
104            Self::Sha2_512 => {
105                let mut hasher = multihash_codetable::Sha2_512::default();
106                self.wrap(hash(&mut hasher, bytes)?)?
107            }
108            Self::Sha3_224 => {
109                let mut hasher = multihash_codetable::Sha3_224::default();
110                self.wrap(hash(&mut hasher, bytes)?)?
111            }
112            Self::Sha3_256 => {
113                let mut hasher = multihash_codetable::Sha3_256::default();
114                self.wrap(hash(&mut hasher, bytes)?)?
115            }
116            Self::Sha3_384 => {
117                let mut hasher = multihash_codetable::Sha3_384::default();
118                self.wrap(hash(&mut hasher, bytes)?)?
119            }
120            Self::Sha3_512 => {
121                let mut hasher = multihash_codetable::Sha3_512::default();
122                self.wrap(hash(&mut hasher, bytes)?)?
123            }
124            Self::Keccak224 => {
125                let mut hasher = multihash_codetable::Keccak224::default();
126                self.wrap(hash(&mut hasher, bytes)?)?
127            }
128            Self::Keccak256 => {
129                let mut hasher = multihash_codetable::Keccak256::default();
130                self.wrap(hash(&mut hasher, bytes)?)?
131            }
132            Self::Keccak384 => {
133                let mut hasher = multihash_codetable::Keccak384::default();
134                self.wrap(hash(&mut hasher, bytes)?)?
135            }
136            Self::Keccak512 => {
137                let mut hasher = multihash_codetable::Keccak512::default();
138                self.wrap(hash(&mut hasher, bytes)?)?
139            }
140            Self::Blake2b256 => {
141                let mut hasher = multihash_codetable::Blake2b256::default();
142                self.wrap(hash(&mut hasher, bytes)?)?
143            }
144            Self::Blake2b512 => {
145                let mut hasher = multihash_codetable::Blake2b512::default();
146                self.wrap(hash(&mut hasher, bytes)?)?
147            }
148            Self::Blake2s128 => {
149                let mut hasher = multihash_codetable::Blake2s128::default();
150                self.wrap(hash(&mut hasher, bytes)?)?
151            }
152            Self::Blake2s256 => {
153                let mut hasher = multihash_codetable::Blake2s256::default();
154                self.wrap(hash(&mut hasher, bytes)?)?
155            }
156            Self::Blake3_256 => {
157                let mut hasher = multihash_codetable::Blake3_256::default();
158                self.wrap(hash(&mut hasher, bytes)?)?
159            }
160            Self::Ripemd160 => {
161                let mut hasher = multihash_codetable::Ripemd160::default();
162                self.wrap(hash(&mut hasher, bytes)?)?
163            }
164            Self::Ripemd256 => {
165                let mut hasher = multihash_codetable::Ripemd256::default();
166                self.wrap(hash(&mut hasher, bytes)?)?
167            }
168            Self::Ripemd320 => {
169                let mut hasher = multihash_codetable::Ripemd320::default();
170                self.wrap(hash(&mut hasher, bytes)?)?
171            }
172            _ => {
173                anyhow::bail!("`digest_byte_stream` is unimplemented for {self:?}");
174            }
175        })
176    }
177}
178
179/// Identity hasher with a maximum size.
180///
181/// # Panics
182///
183/// Panics if the input is bigger than the maximum size.
184/// Ported from <https://github.com/multiformats/rust-multihash/pull/289>
185#[derive(Debug)]
186pub struct IdentityHasher<const S: usize> {
187    i: usize,
188    bytes: [u8; S],
189}
190
191impl<const S: usize> Default for IdentityHasher<S> {
192    fn default() -> Self {
193        Self {
194            i: 0,
195            bytes: [0u8; S],
196        }
197    }
198}
199
200impl<const S: usize> multihash_derive::Hasher for IdentityHasher<S> {
201    fn update(&mut self, input: &[u8]) {
202        let start = self.i.min(self.bytes.len());
203        let end = (self.i + input.len()).min(self.bytes.len());
204        self.bytes[start..end].copy_from_slice(input);
205        self.i = end;
206    }
207
208    fn finalize(&mut self) -> &[u8] {
209        &self.bytes[..self.i]
210    }
211
212    fn reset(&mut self) {
213        self.i = 0
214    }
215}
216
217#[cfg(test)]
218mod tests {
219    use std::io::Cursor;
220
221    use super::*;
222    use crate::utils::rand::forest_rng;
223    use rand::RngCore as _;
224
225    #[test]
226    fn test_digest_byte_stream() {
227        use MultihashCode::*;
228
229        for len in [0, 1, 100, 1024, 10000] {
230            let mut bytes = vec![0; len];
231            forest_rng().fill_bytes(&mut bytes);
232            let mut cursor = Cursor::new(bytes.clone());
233            for code in [
234                Sha2_256, Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512, Keccak224, Keccak256,
235                Keccak384, Keccak512, Blake2b256, Blake2b512, Blake2s128, Blake2s256, Blake3_256,
236                Ripemd160, Ripemd256, Ripemd320,
237            ] {
238                cursor.set_position(0);
239                let mh1 = code.digest(&bytes);
240                let mh2 = code.digest_byte_stream(&mut cursor).unwrap();
241                assert_eq!(mh1, mh2);
242            }
243
244            cursor.set_position(0);
245            Identity.digest_byte_stream(&mut cursor).unwrap_err();
246        }
247    }
248}