fingerprint_struct/
lib.rs

1//! This crate allows for the computation of cryptographic hashes or arbitrary data structures.
2//!
3//! It provides a [`Fingerprint`] trait which represents a type whose hash can be computed.
4//! It's implemented by default for most common types from [`std`].
5//!
6//! It relies on traits from the [`digest`] crate, which means its compatible with all
7//! [hash implementations](https://github.com/RustCrypto/hashes) from the
8//! [Rust Crypto project](https://github.com/RustCrypto/).
9//!
10//! Hashes are considered stable, changes to how a given data structure is hashed will cause
11//! a minor version bump. Note that making a change to your own type definitions might introduce
12//! hash collisions. To avoid this, you can include a version number in your data structures.
13//!
14//! You can include your crate version like this:
15//!
16//! ```
17//! use blake2::Blake2b512;
18//! use fingerprint_struct::fingerprint;
19//!
20//! let payload = "Hello world!";
21//! let hash = fingerprint::<Blake2b512>((env!("CARGO_PKG_VERSION"), payload));
22//! ```
23
24#![cfg_attr(not(feature = "std"), no_std)]
25#[cfg(feature = "alloc")]
26extern crate alloc;
27
28mod impls;
29
30use digest::{FixedOutput, Output, Update};
31
32/// A data structure whose cryptographic hash can be computed by a hasher.
33///
34/// Implementations are provided for common [`std`] types, such as primitives, strings, collections
35/// and smart pointers. Custom implementations can be easily written manually, or derived
36/// automatically using `#[derive(Fingerprint)]`.
37pub trait Fingerprint {
38    /// Use this value to update a hasher.
39    fn fingerprint<U: Update>(&self, hasher: &mut U);
40}
41
42/// Calculate the cryptographic hash of a data structure using the default hasher of a given type.
43///
44/// # Examples
45/// ```
46/// use sha2::Sha512;
47/// use fingerprint_struct::{fingerprint, Fingerprint};
48///
49/// let hash = fingerprint::<Sha512>("Hello world!");
50/// println!("{hash:?}");
51/// ```
52///
53/// ```
54/// use blake2::Blake2b512;
55/// use fingerprint_struct::{fingerprint, Fingerprint};
56///
57/// let hash = fingerprint::<Blake2b512>("Hello world!");
58/// println!("{hash:?}");
59/// ```
60pub fn fingerprint<H: Update + FixedOutput + Default>(value: impl Fingerprint) -> Output<H> {
61    fingerprint_with(value, H::default())
62}
63
64/// Calculate the cryptographic hash of a data structure using provided hasher.
65///
66/// # Examples
67/// ```
68/// use blake2::{digest::Digest, Blake2b512};
69/// use fingerprint_struct::{fingerprint_with, Fingerprint};
70///
71/// let hash = fingerprint_with("Hello world!", Blake2b512::new_with_prefix("Application specific prefix"));
72/// println!("{hash:?}");
73/// ```
74pub fn fingerprint_with<H: Update + FixedOutput, T: Fingerprint>(
75    value: T,
76    mut hasher: H,
77) -> Output<H> {
78    value.fingerprint(&mut hasher);
79    hasher.finalize_fixed()
80}
81
82/// Implements the Fingerprint trait for a custom struct or enum.
83///
84/// Explicit enum discriminants will be used when provided.
85///
86/// # Examples
87/// ```
88/// use fingerprint_struct::Fingerprint;
89///
90/// # #[cfg(feature = "alloc")]
91/// #[derive(Fingerprint)]
92/// struct SearchResult {
93///     title: String,
94///     link: String,
95///     rating: Option<u8>
96/// }
97/// ```
98///
99/// ```
100/// use fingerprint_struct::Fingerprint;
101///
102/// # #[cfg(feature = "alloc")]
103/// #[derive(Fingerprint)]
104/// enum LoginState {
105///     LoggedOut,
106///     LoggedIn { token: String }
107/// }
108/// ```
109#[cfg(feature = "derive")]
110pub use fingerprint_struct_derive::Fingerprint;