multihash_codetable/
lib.rs

1#![cfg_attr(feature = "arb", allow(unreachable_code))] // Otherwise the "Cargo Hack" check fails since "arb" includes no hash algos by default
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5//! A batteries-included code table of multihashes.
6//!
7//! Whilst the `multihash` crate itself only defines the data structure, this crate defines a codetable via [`multihash_derive`] for several hashers.
8//! Although convenient, depending on this crate will increase the dependency footprint of your project.
9//!
10//! It is only recommended as a getting-started-quickly solution.
11//! For production, you should either define your own codetable or rely only on the `multihash` crate itself.
12
13mod hasher_impl;
14
15pub use multihash_derive::MultihashDigest;
16
17#[cfg(feature = "blake2b")]
18#[cfg_attr(docsrs, doc(cfg(feature = "blake2b")))]
19pub use crate::hasher_impl::blake2b::{Blake2b256, Blake2b512, Blake2bHasher};
20#[cfg(feature = "blake2s")]
21#[cfg_attr(docsrs, doc(cfg(feature = "blake2s")))]
22pub use crate::hasher_impl::blake2s::{Blake2s128, Blake2s256, Blake2sHasher};
23#[cfg(feature = "blake3")]
24#[cfg_attr(docsrs, doc(cfg(feature = "blake3")))]
25pub use crate::hasher_impl::blake3::{Blake3Hasher, Blake3_256};
26#[cfg(feature = "ripemd")]
27#[cfg_attr(docsrs, doc(cfg(feature = "ripemd")))]
28pub use crate::hasher_impl::ripemd::{Ripemd160, Ripemd256, Ripemd320};
29#[cfg(feature = "sha1")]
30#[cfg_attr(docsrs, doc(cfg(feature = "sha1")))]
31pub use crate::hasher_impl::sha1::Sha1;
32#[cfg(feature = "sha2")]
33#[cfg_attr(docsrs, doc(cfg(feature = "sha2")))]
34pub use crate::hasher_impl::sha2::{Sha2_256, Sha2_512};
35#[cfg(feature = "sha3")]
36#[cfg_attr(docsrs, doc(cfg(feature = "sha3")))]
37pub use crate::hasher_impl::sha3::{
38    Keccak224, Keccak256, Keccak384, Keccak512, Sha3_224, Sha3_256, Sha3_384, Sha3_512,
39};
40#[cfg(feature = "strobe")]
41#[cfg_attr(docsrs, doc(cfg(feature = "strobe")))]
42pub use crate::hasher_impl::strobe::{Strobe256, Strobe512, StrobeHasher};
43
44/// Default (cryptographically secure) Multihash implementation.
45///
46/// This is a default set of hashing algorithms. Usually applications would use their own subset of
47/// algorithms. See the [`multihash-derive`] crate for more information.
48///
49/// [`multihash-derive`]: https://docs.rs/multihash-derive
50#[cfg_attr(feature = "arb", derive(arbitrary::Arbitrary))]
51#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
52#[derive(Copy, Clone, Debug, Eq, MultihashDigest, PartialEq)]
53#[mh(alloc_size = 64)]
54pub enum Code {
55    /// SHA-256 (32-byte hash size)
56    #[cfg(feature = "sha2")]
57    #[cfg_attr(docsrs, doc(cfg(feature = "sha2")))]
58    #[mh(code = 0x12, hasher = crate::Sha2_256)]
59    Sha2_256,
60    /// SHA-512 (64-byte hash size)
61    #[cfg(feature = "sha2")]
62    #[cfg_attr(docsrs, doc(cfg(feature = "sha2")))]
63    #[mh(code = 0x13, hasher = crate::Sha2_512)]
64    Sha2_512,
65    /// SHA3-224 (28-byte hash size)
66    #[cfg(feature = "sha3")]
67    #[cfg_attr(docsrs, doc(cfg(feature = "sha3")))]
68    #[mh(code = 0x17, hasher = crate::Sha3_224)]
69    Sha3_224,
70    /// SHA3-256 (32-byte hash size)
71    #[cfg(feature = "sha3")]
72    #[cfg_attr(docsrs, doc(cfg(feature = "sha3")))]
73    #[mh(code = 0x16, hasher = crate::Sha3_256)]
74    Sha3_256,
75    /// SHA3-384 (48-byte hash size)
76    #[cfg(feature = "sha3")]
77    #[cfg_attr(docsrs, doc(cfg(feature = "sha3")))]
78    #[mh(code = 0x15, hasher = crate::Sha3_384)]
79    Sha3_384,
80    /// SHA3-512 (64-byte hash size)
81    #[cfg(feature = "sha3")]
82    #[cfg_attr(docsrs, doc(cfg(feature = "sha3")))]
83    #[mh(code = 0x14, hasher = crate::Sha3_512)]
84    Sha3_512,
85    /// Keccak-224 (28-byte hash size)
86    #[cfg(feature = "sha3")]
87    #[cfg_attr(docsrs, doc(cfg(feature = "sha3")))]
88    #[mh(code = 0x1a, hasher = crate::Keccak224)]
89    Keccak224,
90    /// Keccak-256 (32-byte hash size)
91    #[cfg(feature = "sha3")]
92    #[cfg_attr(docsrs, doc(cfg(feature = "sha3")))]
93    #[mh(code = 0x1b, hasher = crate::Keccak256)]
94    Keccak256,
95    /// Keccak-384 (48-byte hash size)
96    #[cfg(feature = "sha3")]
97    #[cfg_attr(docsrs, doc(cfg(feature = "sha3")))]
98    #[mh(code = 0x1c, hasher = crate::Keccak384)]
99    Keccak384,
100    /// Keccak-512 (64-byte hash size)
101    #[cfg(feature = "sha3")]
102    #[cfg_attr(docsrs, doc(cfg(feature = "sha3")))]
103    #[mh(code = 0x1d, hasher = crate::Keccak512)]
104    Keccak512,
105    /// BLAKE2b-256 (32-byte hash size)
106    #[cfg(feature = "blake2b")]
107    #[cfg_attr(docsrs, doc(cfg(feature = "blake2b")))]
108    #[mh(code = 0xb220, hasher = crate::Blake2b256)]
109    Blake2b256,
110    /// BLAKE2b-512 (64-byte hash size)
111    #[cfg(feature = "blake2b")]
112    #[cfg_attr(docsrs, doc(cfg(feature = "blake2b")))]
113    #[mh(code = 0xb240, hasher = crate::Blake2b512)]
114    Blake2b512,
115    /// BLAKE2s-128 (16-byte hash size)
116    #[cfg(feature = "blake2s")]
117    #[cfg_attr(docsrs, doc(cfg(feature = "blake2s")))]
118    #[mh(code = 0xb250, hasher = crate::Blake2s128)]
119    Blake2s128,
120    /// BLAKE2s-256 (32-byte hash size)
121    #[cfg(feature = "blake2s")]
122    #[cfg_attr(docsrs, doc(cfg(feature = "blake2s")))]
123    #[mh(code = 0xb260, hasher = crate::Blake2s256)]
124    Blake2s256,
125    /// BLAKE3-256 (32-byte hash size)
126    #[cfg(feature = "blake3")]
127    #[cfg_attr(docsrs, doc(cfg(feature = "blake3")))]
128    #[mh(code = 0x1e, hasher = crate::Blake3_256)]
129    Blake3_256,
130    /// RIPEMD-160 (20-byte hash size)
131    #[cfg(feature = "ripemd")]
132    #[cfg_attr(docsrs, doc(cfg(feature = "ripemd")))]
133    #[mh(code = 0x1053, hasher = crate::Ripemd160)]
134    Ripemd160,
135    /// RIPEMD-256 (32-byte hash size)
136    #[cfg(feature = "ripemd")]
137    #[cfg_attr(docsrs, doc(cfg(feature = "ripemd")))]
138    #[mh(code = 0x1054, hasher = crate::Ripemd256)]
139    Ripemd256,
140    /// RIPEMD-320 (40-byte hash size)
141    #[cfg(feature = "ripemd")]
142    #[cfg_attr(docsrs, doc(cfg(feature = "ripemd")))]
143    #[mh(code = 0x1055, hasher = crate::Ripemd320)]
144    Ripemd320,
145}
146
147#[cfg(all(test, any(feature = "sha2", feature = "sha3")))]
148mod tests {
149    use super::*;
150    #[cfg(feature = "sha3")]
151    use crate::hasher_impl::sha3::{Sha3_256, Sha3_512};
152    #[cfg(feature = "sha3")]
153    use multihash_derive::Hasher;
154    #[cfg(feature = "sha2")]
155    use multihash_derive::{Multihash, MultihashDigest};
156
157    #[test]
158    #[cfg(feature = "sha3")]
159    fn test_hasher_256() {
160        let mut hasher = Sha3_256::default();
161        hasher.update(b"hello world");
162        let digest = hasher.finalize();
163        let hash = Code::Sha3_256.wrap(digest).unwrap();
164        let hash2 = Code::Sha3_256.digest(b"hello world");
165        assert_eq!(hash.code(), u64::from(Code::Sha3_256));
166        assert_eq!(hash.size(), 32);
167        assert_eq!(hash.digest(), digest);
168        assert_eq!(hash, hash2);
169    }
170
171    #[test]
172    #[cfg(feature = "sha3")]
173    fn test_hasher_512() {
174        let mut hasher = Sha3_512::default();
175        hasher.update(b"hello world");
176        let digest = hasher.finalize();
177        let hash = Code::Sha3_512.wrap(digest).unwrap();
178        let hash2 = Code::Sha3_512.digest(b"hello world");
179        assert_eq!(hash.code(), u64::from(Code::Sha3_512));
180        assert_eq!(hash.size(), 64);
181        assert_eq!(hash.digest(), digest);
182        assert_eq!(hash, hash2);
183    }
184
185    #[test]
186    #[cfg(feature = "sha2")]
187    fn roundtrip() {
188        let hash = Code::Sha2_256.digest(b"hello world");
189        let mut buf = [0u8; 35];
190        let written = hash.write(&mut buf[..]).unwrap();
191        let hash2 = Multihash::<32>::read(&buf[..]).unwrap();
192        assert_eq!(hash, hash2);
193        assert_eq!(hash.encoded_len(), written);
194    }
195
196    #[test]
197    #[cfg(feature = "sha2")]
198    fn test_truncate_down() {
199        let hash = Code::Sha2_256.digest(b"hello world");
200        let small = hash.truncate(20);
201        assert_eq!(small.size(), 20);
202    }
203
204    #[test]
205    #[cfg(feature = "sha2")]
206    fn test_truncate_up() {
207        let hash = Code::Sha2_256.digest(b"hello world");
208        let small = hash.truncate(100);
209        assert_eq!(small.size(), 32);
210    }
211
212    #[test]
213    #[cfg(feature = "sha2")]
214    fn test_resize_fits() {
215        let hash = Code::Sha2_256.digest(b"hello world");
216        let _: Multihash<32> = hash.resize().unwrap();
217    }
218
219    #[test]
220    #[cfg(feature = "sha2")]
221    fn test_resize_up() {
222        let hash = Code::Sha2_256.digest(b"hello world");
223        let _: Multihash<100> = hash.resize().unwrap();
224    }
225
226    #[test]
227    #[cfg(feature = "sha2")]
228    fn test_resize_truncate() {
229        let hash = Code::Sha2_256.digest(b"hello world");
230        hash.resize::<20>().unwrap_err();
231    }
232}