deterministic_hash/lib.rs
1//! Tiny Rust library to create deterministic hashes regardless of architecture. This library is `no-std` compatible and uses no allocations or dependencies.
2//!
3//! The default `core::hash::Hasher` implementation ensures a platform dependant hashing of datastructures that use `#[derive(Hash)]`. Most notably by:
4//! * using `to_ne_bytes` for `u{8,16,32,64,128}`.
5//! * using the native bytelength of `usize`.
6//!
7//! The `DeterministicHasher` of this library forces the use of `to_le_bytes` and casts `usize` to `u64` regardless of your platform. Hence the hasher will be less efficient, but will be deterministic when using the same library in different architecture contexts. I use a common dataprotocol library both on ARM embedded systems, wasm and x64.
8//!
9//! From any hasher make it deterministic by inserting `DeterministicHasher` in between:
10//! ```
11//! let hasher = crc::crc32::Digest::new(crc::crc32::KOOPMAN);
12//! let hasher = deterministic_hash::DeterministicHasher::new(hasher);
13//! ```
14
15#![no_std]
16use core::hash::Hasher;
17
18/// Wrapper around any hasher to make it deterministic.
19///
20/// ```
21/// use core::hash::Hash;
22/// use crc::crc32::Hasher32;
23/// use deterministic_hash::DeterministicHasher;
24/// let mut hasher = DeterministicHasher::new(crc::crc32::Digest::new(crc::crc32::KOOPMAN));
25/// (0x1337 as usize).hash(&mut hasher);
26/// assert_eq!(hasher.as_inner().sum32(), 2482448842);
27/// ```
28#[derive(Default, Clone, Debug)]
29pub struct DeterministicHasher<T: Hasher>(T);
30
31impl<T: Hasher> DeterministicHasher<T> {
32 pub fn new(inner: T) -> Self {
33 Self(inner)
34 }
35
36 pub fn as_inner(&self) -> &T {
37 &self.0
38 }
39
40 pub fn into_inner(self) -> T {
41 self.0
42 }
43}
44
45/// Implementation of hasher that forces all bytes written to be platform agnostic.
46impl<T: Hasher> core::hash::Hasher for DeterministicHasher<T> {
47 fn finish(&self) -> u64 {
48 self.0.finish()
49 }
50
51 fn write(&mut self, bytes: &[u8]) {
52 self.0.write(bytes);
53 }
54
55 fn write_u8(&mut self, i: u8) {
56 self.write(&i.to_le_bytes())
57 }
58
59 fn write_u16(&mut self, i: u16) {
60 self.write(&i.to_le_bytes())
61 }
62
63 fn write_u32(&mut self, i: u32) {
64 self.write(&i.to_le_bytes())
65 }
66
67 fn write_u64(&mut self, i: u64) {
68 self.write(&i.to_le_bytes())
69 }
70
71 fn write_u128(&mut self, i: u128) {
72 self.write(&i.to_le_bytes())
73 }
74
75 fn write_usize(&mut self, i: usize) {
76 self.write(&(i as u64).to_le_bytes())
77 }
78
79 fn write_i8(&mut self, i: i8) {
80 self.write_u8(i as u8)
81 }
82
83 fn write_i16(&mut self, i: i16) {
84 self.write_u16(i as u16)
85 }
86
87 fn write_i32(&mut self, i: i32) {
88 self.write_u32(i as u32)
89 }
90
91 fn write_i64(&mut self, i: i64) {
92 self.write_u64(i as u64)
93 }
94
95 fn write_i128(&mut self, i: i128) {
96 self.write_u128(i as u128)
97 }
98
99 fn write_isize(&mut self, i: isize) {
100 self.write_usize(i as usize)
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 #[test]
107 fn it_works() {
108 assert_eq!(2 + 2, 4);
109 }
110}