1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use std::io;
use std::io::Write;

use digest::consts::{U128, U16, U20, U512, U64};
use digest::generic_array::GenericArray;
use digest::typenum::Unsigned;
use digest::{ExtendableOutput, HashMarker, Output, Update};

pub trait FixedDigest: Update + digest::FixedOutput + Default + HashMarker {}
impl<T> FixedDigest for T
where
    T: Update + digest::FixedOutput + Default + HashMarker,
    [(); T::OutputSize::USIZE]:,
    [u8; T::OutputSize::USIZE]: From<GenericArray<u8, T::OutputSize>>,
{
}

pub struct HashWriter<H>(pub H)
where
    H: Update;

impl<H> Write for HashWriter<H>
where
    H: Update,
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.update(buf);
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

pub type B3_256 = blake3::Hasher;

macro_rules! impl_b3_xof {
    ($name:ident, $size:ty) => {
        #[derive(Default)]
        pub struct $name {
            inner: blake3::Hasher,
        }

        impl $name {
            pub fn new() -> Self {
                Self::default()
            }
        }

        impl Update for $name {
            fn update(&mut self, data: &[u8]) {
                Update::update(&mut self.inner, data);
            }
        }

        impl HashMarker for $name {}

        impl digest::OutputSizeUser for $name {
            type OutputSize = $size;
        }

        impl digest::FixedOutput for $name {
            fn finalize_into(self, out: &mut Output<Self>) {
                self.inner.finalize_xof_into(out);
            }
        }
    };
}

impl_b3_xof!(B3_128, U16);
impl_b3_xof!(B3_160, U20);
impl_b3_xof!(B3_512, U64);
impl_b3_xof!(B3_1024, U128);
impl_b3_xof!(B3_2048, U512);