Skip to main content

lexe_sha256/
sha256.rs

1use std::{hash::Hasher, io};
2
3use lexe_byte_array::ByteArray;
4use ref_cast::RefCast;
5
6pub const HASH_LEN: usize = 32;
7
8/// A SHA-256 Hash value.
9#[derive(Copy, Clone, Default, Eq, Hash, PartialEq, RefCast)]
10#[repr(transparent)]
11pub struct Hash([u8; 32]);
12
13/// A SHA-256 digest accumulator.
14#[derive(Clone)]
15pub struct Context(ring::digest::Context);
16
17/// SHA-256 digest a single input.
18pub fn digest(input: &[u8]) -> Hash {
19    digest_many(&[input])
20}
21
22/// SHA-256 digest several input slices concatenated together, without
23/// allocating.
24pub fn digest_many(inputs: &[&[u8]]) -> Hash {
25    let mut ctx = Context::new();
26    for input in inputs {
27        ctx.update(input);
28    }
29    ctx.finish()
30}
31
32// -- impl Hash -- //
33
34impl Hash {
35    pub const fn new(value: [u8; 32]) -> Self {
36        Self(value)
37    }
38
39    // Note: not pub, since `ring::digest::Digest` is not always SHA-256, but
40    // we can guarantee this invariant inside the module.
41    fn from_ring(output: ring::digest::Digest) -> Self {
42        Self::new(<[u8; 32]>::try_from(output.as_ref()).unwrap())
43    }
44}
45
46lexe_byte_array::impl_byte_array!(Hash, 32);
47lexe_byte_array::impl_fromstr_fromhex!(Hash, 32);
48lexe_byte_array::impl_debug_display_as_hex!(Hash);
49
50// -- impl Context -- //
51
52impl Context {
53    pub fn new() -> Self {
54        Self(ring::digest::Context::new(&ring::digest::SHA256))
55    }
56
57    pub fn update(&mut self, input: &[u8]) {
58        self.0.update(input);
59    }
60
61    pub fn finish(self) -> Hash {
62        Hash::from_ring(self.0.finish())
63    }
64}
65
66impl Default for Context {
67    fn default() -> Self {
68        Self::new()
69    }
70}
71
72impl Hasher for Context {
73    fn finish(&self) -> u64 {
74        let hash = self.clone().finish();
75        u64::from_le_bytes(hash.as_array()[..8].try_into().unwrap())
76    }
77
78    fn write(&mut self, bytes: &[u8]) {
79        self.update(bytes);
80    }
81}
82
83impl io::Write for Context {
84    fn write(&mut self, input: &[u8]) -> io::Result<usize> {
85        self.update(input);
86        Ok(input.len())
87    }
88
89    fn flush(&mut self) -> io::Result<()> {
90        Ok(())
91    }
92}
93
94#[cfg(test)]
95mod test {
96    use lexe_hex::hex;
97
98    use crate::sha256;
99
100    // sanity check
101    #[test]
102    fn test_sha256() {
103        let actual = hex::encode(sha256::digest(b"").as_ref());
104        let expected =
105            "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
106        assert_eq!(&actual, expected);
107    }
108}