simple_hash/
lib.rs

1//! A simple interface for hashing rust values
2//!
3//! This crates defines two traits: [Hasher] and [Hashable].
4//!
5//! The first represents an hashing algorithm and state, and is currently implemented
6//! for [sha2::Sha256].
7//!
8//! The second is implemented for any rust value that needs to be hashed.
9//! An Helper derive macro with the same name is provided to avoid boilerplate.
10//!
11//! The current set of std types that implement [Hashable] is limited. PRs are welcome.
12//!
13//! Example use:
14//!
15//! ```
16//! use simple_hash::Hashable;
17//! #[derive(Hashable)]
18//! struct Foo {
19//!     a: u8,
20//!     b: u16,
21//!     c: Vec<u32>,
22//! }
23//! let foo = Foo {
24//!     a: 8,
25//!     b: 99,
26//!     c: vec![0,1,2,3],
27//! };
28//! let res = foo.digest::<sha2::Sha256>();
29//! assert_eq!(res, hex_literal::hex!("929863ce588951eae0cc88755216f96951d431e7d15adbb836d8f1960bb65a9d"));
30//! ```
31//!
32use sha2::Sha256;
33use sha2::Digest;
34use byteorder::{LittleEndian, WriteBytesExt};
35use paste::paste;
36
37pub use simple_hash_macro::Hashable;
38
39pub trait Hasher {
40    type Output;
41    fn update<D: AsRef<[u8]>>(&mut self, data: D);
42    fn finish(self) -> Self::Output;
43    fn digest<H: Hashable>(data: &H) -> Self::Output;
44}
45
46pub trait Hashable {
47    fn update<H: Hasher>(&self, h: &mut H);
48    fn digest<H: Hasher>(&self) -> <H as Hasher>::Output where Self: Sized {
49        H::digest(self)
50    }
51}
52
53impl Hasher for Sha256 {
54    type Output = [u8; 32];
55
56    fn update<D: AsRef<[u8]>>(&mut self, data: D) {
57        Digest::update(self, data);
58    }
59    fn finish(self) -> Self::Output {
60        let res = self.finalize();
61        let mut out = [0; 32];
62        for i in 0..res.len() {
63            out[i] = res[i];
64        }
65        out
66    }
67    fn digest<H: Hashable>(data: &H) -> Self::Output {
68        let mut sha = Sha256::new();
69        data.update(&mut sha);
70        sha.finish()
71    }
72}
73
74impl Hashable for u8 {
75    fn update<H: Hasher>(&self, h: &mut H) {
76        let mut buf = [0u8; std::mem::size_of::<u8>()];
77        let mut b = &mut buf[..];
78        b.write_u8(*self).unwrap();
79        h.update(buf.as_slice());
80    }
81}
82impl Hashable for bool {
83    fn update<H: Hasher>(&self, h: &mut H) {
84        let mut buf = [0u8; std::mem::size_of::<u8>()];
85        let mut b = &mut buf[..];
86        b.write_u8(*self as u8).unwrap();
87        h.update(buf.as_slice());
88    }
89}
90impl Hashable for i8 {
91    fn update<H: Hasher>(&self, h: &mut H) {
92        let mut buf = [0u8; std::mem::size_of::<u8>()];
93        let mut b = &mut buf[..];
94        b.write_i8(*self).unwrap();
95        h.update(buf.as_slice());
96    }
97}
98
99macro_rules! impl_hashable_for {
100    ($t:ty) => {
101        impl crate::Hashable for $t {
102            fn update<H: Hasher>(&self, h: &mut H) {
103                let mut buf = [0u8; std::mem::size_of::<$t>()];
104                let mut b = &mut buf[..];
105                paste! {
106                    b.[<write_ $t>]::<LittleEndian>(*self).unwrap();
107                }
108                h.update(buf.as_slice());
109            }
110        }
111    };
112}
113
114impl_hashable_for!(i16);
115impl_hashable_for!(u16);
116impl_hashable_for!(i32);
117impl_hashable_for!(u32);
118impl_hashable_for!(i64);
119impl_hashable_for!(u64);
120
121
122impl<T: Hashable> Hashable for Vec<T> {
123    fn update<H: Hasher>(&self, h: &mut H) {
124        for t in self {
125            t.update(h);
126        }
127    }
128}
129impl Hashable for String {
130    fn update<H: Hasher>(&self, h: &mut H) {
131        for t in self.as_bytes() {
132            t.update(h);
133        }
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140    use crate as simple_hash;
141
142    #[derive(Hashable)]
143    struct Foo {
144        a: u8,
145        b: u16,
146        c: Vec<u32>,
147    }
148    #[test]
149    fn test_u8() {
150        let res = (9u8).digest::<sha2::Sha256>();
151        assert_eq!(res, hex_literal::hex!("2b4c342f5433ebe591a1da77e013d1b72475562d48578dca8b84bac6651c3cb9"));
152    }
153    #[test]
154    fn test_derive() {
155        let foo = Foo {
156            a: 8,
157            b: 99,
158            c: vec![0,1,2,3],
159        };
160        let res = foo.digest::<sha2::Sha256>();
161        assert_eq!(res, hex_literal::hex!("929863ce588951eae0cc88755216f96951d431e7d15adbb836d8f1960bb65a9d"));
162    }
163}