chf/lib.rs
1// SPDX-License-Identifier: CC0-1.0
2
3//! Rust Cryptographic Hash Functions.
4//!
5//! This is a simple, no-dependency library which implements crypotographic hash
6//! functions. At the moment this includes:
7//! - SHA-1
8//! - SHA-2
9//! - SHA-256
10//! - SHA-384
11//! - SHA-512
12//! - SHA-512/256
13//! - RIPEMD-160
14//! - SipHash-2-4
15//! - HMAC-x (where x is any of the hash functions above).
16//! - Domain separation using tagged SHA-256.
17//!
18//! ## Commonly used operations
19//!
20//! Hashing a single byte slice or a string:
21//!
22//! ```rust
23//! use chf::sha256;
24//!
25//! let bytes = [0u8; 5];
26//! let hash_of_bytes = sha256::Hash::hash(&bytes);
27//! let hash_of_string = sha256::Hash::hash("some string".as_bytes());
28//! ```
29//!
30//!
31//! Hashing content from a reader:
32//!
33//! ```rust
34//! use chf::sha256;
35//!
36//! #[cfg(std)]
37//! # fn main() -> std::io::Result<()> {
38//! let mut reader: &[u8] = b"hello"; // in real code, this could be a `File` or `TcpStream`
39//! let mut engine = sha256::Engine::default();
40//! std::io::copy(&mut reader, &mut engine)?;
41//! let hash = sha256::Hash::from_engine(engine);
42//! # Ok(())
43//! # }
44//!
45//! #[cfg(not(std))]
46//! # fn main() {}
47//! ```
48//!
49//!
50//! Hashing content by [`std::io::Write`] on HashEngine:
51//!
52//! ```rust
53//! use chf::sha256;
54//! use std::io::Write;
55//!
56//! #[cfg(std)]
57//! # fn main() -> std::io::Result<()> {
58//! let mut part1: &[u8] = b"hello";
59//! let mut part2: &[u8] = b" ";
60//! let mut part3: &[u8] = b"world";
61//! let mut engine = sha256::Engine::default();
62//! engine.write_all(part1)?;
63//! engine.write_all(part2)?;
64//! engine.write_all(part3)?;
65//! let hash = sha256::Hash::from_engine(engine);
66//! # Ok(())
67//! # }
68//!
69//! #[cfg(not(std))]
70//! # fn main() {}
71//! ```
72
73#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
74// Experimental features we need.
75#![cfg_attr(docsrs, feature(doc_auto_cfg))]
76#![cfg_attr(bench, feature(test))]
77// Coding conventions.
78#![warn(missing_docs)]
79// Instead of littering the codebase for non-fuzzing code just globally allow.
80#![cfg_attr(hashes_fuzz, allow(dead_code, unused_imports))]
81// Exclude lints we don't think are valuable.
82#![allow(clippy::needless_question_mark)] // https://github.com/rust-bitcoin/rust-bitcoin/pull/2134
83#![allow(clippy::manual_range_contains)] // More readable than clippy's format.
84#![allow(clippy::needless_borrows_for_generic_args)] // https://github.com/rust-lang/rust-clippy/issues/12454
85
86#[cfg(all(feature = "alloc", not(feature = "std")))]
87extern crate alloc;
88#[cfg(any(test, feature = "std"))]
89extern crate core;
90
91#[cfg(feature = "serde")]
92/// A generic serialization/deserialization framework.
93pub extern crate serde;
94
95#[cfg(all(test, feature = "serde"))]
96extern crate serde_test;
97#[cfg(bench)]
98extern crate test;
99
100/// Re-export the `hex-conservative` crate.
101pub extern crate hex;
102
103#[doc(hidden)]
104pub mod _export {
105 /// A re-export of core::*
106 pub mod _core {
107 pub use core::*;
108 }
109}
110
111#[cfg(feature = "schemars")]
112extern crate schemars;
113
114mod internal_macros;
115#[macro_use]
116pub mod serde_macros;
117pub mod cmp;
118pub mod hmac;
119#[cfg(feature = "bitcoin-io")]
120mod impls;
121pub mod ripemd160;
122pub mod sha1;
123pub mod sha256;
124pub mod sha256t;
125pub mod sha384;
126pub mod sha512;
127pub mod sha512_256;
128pub mod siphash24;
129
130use core::{convert, fmt, hash};
131
132/// A hashing engine which bytes can be serialized into.
133pub trait HashEngine: Clone + Default {
134 /// The digest returned by this hash engine.
135 ///
136 /// This is expected to be an array.
137 // trait const types don't work as one would think without nightly.
138 // ref: https://users.rust-lang.org/t/error-e0401-cant-use-generic-parameters-from-outer-function/84512
139 type Digest: Copy
140 + Clone
141 + PartialEq
142 + Eq
143 + PartialOrd
144 + Ord
145 + hash::Hash
146 + convert::AsRef<[u8]>;
147
148 /// Byte array representing the internal state of the hash engine.
149 type Midstate;
150
151 /// Length of the hash's internal block size, in bytes.
152 const BLOCK_SIZE: usize;
153
154 /// Creates a new hash engine.
155 fn new() -> Self { Default::default() }
156
157 /// Add data to the hash engine.
158 fn input(&mut self, data: &[u8]);
159
160 /// Return the number of bytes already n_bytes_hashed(inputted).
161 fn n_bytes_hashed(&self) -> usize;
162
163 /// Returns the final digest from the current state of the hash engine.
164 fn finalize(self) -> Self::Digest;
165
166 /// Creates a default hash engine, adds `bytes` to it, then finalizes the engine.
167 ///
168 /// # Returns
169 ///
170 /// The digest created by hashing `bytes` with engine's hashing algorithm.
171 fn hash(bytes: &[u8]) -> Self::Digest {
172 let mut engine = Self::new();
173 engine.input(bytes);
174 engine.finalize()
175 }
176
177 /// Hashes all the byte slices retrieved from the iterator together.
178 fn hash_byte_chunks<B, I>(byte_slices: I) -> Self::Digest
179 where
180 B: AsRef<[u8]>,
181 I: IntoIterator<Item = B>,
182 {
183 let mut engine = Self::new();
184 for slice in byte_slices {
185 engine.input(slice.as_ref());
186 }
187 engine.finalize()
188 }
189
190 /// Outputs the midstate of the hash engine. This function should not be
191 /// used directly unless you really know what you're doing.
192 fn midstate(&self) -> Self::Midstate;
193
194 /// Create a new [`HashEngine`] from a [`Self::Midstate`].
195 ///
196 /// Only use this function if you know what you are doing.
197 fn from_midstate(midstate: Self::Midstate, length: usize) -> Self;
198}
199
200/// Attempted to create a hash from an invalid length slice.
201#[derive(Debug, Clone, PartialEq, Eq)]
202pub struct FromSliceError {
203 /// The expected slice length.
204 pub expected: usize,
205 /// The erroneous slice length.
206 pub got: usize,
207}
208
209impl FromSliceError {
210 /// Creates a new error (args are the same order as standard error code order).
211 pub fn new(got: usize, expected: usize) -> Self { Self { got, expected } }
212
213 /// Returns the expected slice length.
214 pub fn expected_length(&self) -> usize { self.expected }
215
216 /// Returns the invalid slice length.
217 pub fn invalid_length(&self) -> usize { self.got }
218}
219
220impl fmt::Display for FromSliceError {
221 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
222 write!(f, "invalid slice length {} (expected {})", self.got, self.expected)
223 }
224}
225
226#[cfg(feature = "std")]
227impl std::error::Error for FromSliceError {}