bitcoin_hashes/
lib.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Rust hashes library.
4//!
5//! This is a simple, no-dependency library which implements the hash functions
6//! needed by Bitcoin. These are SHA256, SHA256d, and RIPEMD160. As an ancillary
7//! thing, it exposes hexadecimal serialization and deserialization, since these
8//! are needed to display hashes anway.
9//!
10//! ## Commonly used operations
11//!
12//! Hashing a single byte slice or a string:
13//!
14//! ```rust
15//! use bitcoin_hashes::sha256;
16//! use bitcoin_hashes::Hash;
17//!
18//! let bytes = [0u8; 5];
19//! let hash_of_bytes = sha256::Hash::hash(&bytes);
20//! let hash_of_string = sha256::Hash::hash("some string".as_bytes());
21//! ```
22//!
23//!
24//! Hashing content from a reader:
25//!
26//! ```rust
27//! use bitcoin_hashes::sha256;
28//! use bitcoin_hashes::Hash;
29//!
30//! #[cfg(std)]
31//! # fn main() -> std::io::Result<()> {
32//! let mut reader: &[u8] = b"hello"; // in real code, this could be a `File` or `TcpStream`
33//! let mut engine = sha256::HashEngine::default();
34//! std::io::copy(&mut reader, &mut engine)?;
35//! let hash = sha256::Hash::from_engine(engine);
36//! # Ok(())
37//! # }
38//!
39//! #[cfg(not(std))]
40//! # fn main() {}
41//! ```
42//!
43//!
44//! Hashing content by [`std::io::Write`] on HashEngine:
45//!
46//! ```rust
47//! use bitcoin_hashes::sha256;
48//! use bitcoin_hashes::Hash;
49//! use std::io::Write;
50//!
51//! #[cfg(std)]
52//! # fn main() -> std::io::Result<()> {
53//! let mut part1: &[u8] = b"hello";
54//! let mut part2: &[u8] = b" ";
55//! let mut part3: &[u8] = b"world";
56//! let mut engine = sha256::HashEngine::default();
57//! engine.write_all(part1)?;
58//! engine.write_all(part2)?;
59//! engine.write_all(part3)?;
60//! let hash = sha256::Hash::from_engine(engine);
61//! # Ok(())
62//! # }
63//!
64//! #[cfg(not(std))]
65//! # fn main() {}
66//! ```
67
68#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
69// Experimental features we need.
70#![cfg_attr(bench, feature(test))]
71// Coding conventions.
72#![warn(missing_docs)]
73// Instead of littering the codebase for non-fuzzing code just globally allow.
74#![cfg_attr(hashes_fuzz, allow(dead_code, unused_imports))]
75// Exclude lints we don't think are valuable.
76#![allow(clippy::needless_question_mark)] // https://github.com/rust-bitcoin/rust-bitcoin/pull/2134
77#![allow(clippy::manual_range_contains)] // More readable than clippy's format.
78#![allow(clippy::needless_borrows_for_generic_args)] // https://github.com/rust-lang/rust-clippy/issues/12454
79
80#[cfg(feature = "alloc")]
81extern crate alloc;
82#[cfg(any(test, feature = "std"))]
83extern crate core;
84
85#[cfg(feature = "serde")]
86/// A generic serialization/deserialization framework.
87pub extern crate serde;
88
89#[cfg(all(test, feature = "serde"))]
90extern crate serde_test;
91#[cfg(bench)]
92extern crate test;
93
94/// Re-export the `hex-conservative` crate.
95pub extern crate hex;
96
97#[doc(hidden)]
98pub mod _export {
99    /// A re-export of core::*
100    pub mod _core {
101        pub use core::*;
102    }
103}
104
105#[cfg(feature = "schemars")]
106extern crate actual_schemars as schemars;
107
108mod internal_macros;
109#[macro_use]
110mod util;
111#[macro_use]
112pub mod serde_macros;
113pub mod cmp;
114pub mod hash160;
115pub mod hmac;
116#[cfg(feature = "bitcoin-io")]
117mod impls;
118pub mod ripemd160;
119pub mod sha1;
120pub mod sha256;
121pub mod sha256d;
122pub mod sha256t;
123pub mod sha384;
124pub mod sha512;
125pub mod sha512_256;
126pub mod siphash24;
127
128use core::{borrow, fmt, hash, ops};
129
130pub use hmac::{Hmac, HmacEngine};
131
132/// A hashing engine which bytes can be serialized into.
133pub trait HashEngine: Clone + Default {
134    /// Byte array representing the internal state of the hash engine.
135    type MidState;
136
137    /// Outputs the midstate of the hash engine. This function should not be
138    /// used directly unless you really know what you're doing.
139    fn midstate(&self) -> Self::MidState;
140
141    /// Length of the hash's internal block size, in bytes.
142    const BLOCK_SIZE: usize;
143
144    /// Add data to the hash engine.
145    fn input(&mut self, data: &[u8]);
146
147    /// Return the number of bytes already n_bytes_hashed(inputted).
148    fn n_bytes_hashed(&self) -> usize;
149}
150
151/// Trait which applies to hashes of all types.
152pub trait Hash:
153    Copy
154    + Clone
155    + PartialEq
156    + Eq
157    + PartialOrd
158    + Ord
159    + hash::Hash
160    + fmt::Debug
161    + fmt::Display
162    + fmt::LowerHex
163    + ops::Index<ops::RangeFull, Output = [u8]>
164    + ops::Index<ops::RangeFrom<usize>, Output = [u8]>
165    + ops::Index<ops::RangeTo<usize>, Output = [u8]>
166    + ops::Index<ops::Range<usize>, Output = [u8]>
167    + ops::Index<usize, Output = u8>
168    + borrow::Borrow<[u8]>
169{
170    /// A hashing engine which bytes can be serialized into. It is expected
171    /// to implement the `io::Write` trait, and to never return errors under
172    /// any conditions.
173    type Engine: HashEngine;
174
175    /// The byte array that represents the hash internally.
176    type Bytes: hex::FromHex + Copy;
177
178    /// Constructs a new engine.
179    fn engine() -> Self::Engine { Self::Engine::default() }
180
181    /// Produces a hash from the current state of a given engine.
182    fn from_engine(e: Self::Engine) -> Self;
183
184    /// Length of the hash, in bytes.
185    const LEN: usize;
186
187    /// Copies a byte slice into a hash object.
188    fn from_slice(sl: &[u8]) -> Result<Self, FromSliceError>;
189
190    /// Hashes some bytes.
191    fn hash(data: &[u8]) -> Self {
192        let mut engine = Self::engine();
193        engine.input(data);
194        Self::from_engine(engine)
195    }
196
197    /// Hashes all the byte slices retrieved from the iterator together.
198    fn hash_byte_chunks<B, I>(byte_slices: I) -> Self
199    where
200        B: AsRef<[u8]>,
201        I: IntoIterator<Item = B>,
202    {
203        let mut engine = Self::engine();
204        for slice in byte_slices {
205            engine.input(slice.as_ref());
206        }
207        Self::from_engine(engine)
208    }
209
210    /// Flag indicating whether user-visible serializations of this hash
211    /// should be backward. For some reason Satoshi decided this should be
212    /// true for `Sha256dHash`, so here we are.
213    const DISPLAY_BACKWARD: bool = false;
214
215    /// Returns the underlying byte array.
216    fn to_byte_array(self) -> Self::Bytes;
217
218    /// Returns a reference to the underlying byte array.
219    fn as_byte_array(&self) -> &Self::Bytes;
220
221    /// Constructs a hash from the underlying byte array.
222    fn from_byte_array(bytes: Self::Bytes) -> Self;
223
224    /// Returns an all zero hash.
225    ///
226    /// An all zeros hash is a made up construct because there is not a known input that can create
227    /// it, however it is used in various places in Bitcoin e.g., the Bitcoin genesis block's
228    /// previous blockhash and the coinbase transaction's outpoint txid.
229    fn all_zeros() -> Self;
230}
231
232/// Attempted to create a hash from an invalid length slice.
233#[derive(Debug, Clone, PartialEq, Eq)]
234pub struct FromSliceError {
235    expected: usize,
236    got: usize,
237}
238
239impl FromSliceError {
240    /// Returns the expected slice length.
241    pub fn expected_length(&self) -> usize { self.expected }
242
243    /// Returns the invalid slice length.
244    pub fn invalid_length(&self) -> usize { self.got }
245}
246
247impl fmt::Display for FromSliceError {
248    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
249        write!(f, "invalid slice length {} (expected {})", self.got, self.expected)
250    }
251}
252
253#[cfg(feature = "std")]
254impl std::error::Error for FromSliceError {}
255
256#[cfg(test)]
257mod tests {
258    use crate::{sha256d, Hash};
259
260    hash_newtype! {
261        /// A test newtype
262        struct TestNewtype(sha256d::Hash);
263
264        /// A test newtype
265        struct TestNewtype2(sha256d::Hash);
266    }
267
268    #[test]
269    fn convert_newtypes() {
270        let h1 = TestNewtype::hash(&[]);
271        let h2: TestNewtype2 = h1.to_raw_hash().into();
272        assert_eq!(&h1[..], &h2[..]);
273
274        let h = sha256d::Hash::hash(&[]);
275        let h2: TestNewtype = h.to_string().parse().unwrap();
276        assert_eq!(h2.to_raw_hash(), h);
277    }
278
279    #[test]
280    fn newtype_fmt_roundtrip() {
281        let orig = TestNewtype::hash(&[]);
282        let hex = format!("{}", orig);
283        let rinsed = hex.parse::<TestNewtype>().expect("failed to parse hex");
284        assert_eq!(rinsed, orig)
285    }
286}