blake3/
guts.rs

1//! This undocumented and unstable module is for use cases like the `bao` crate,
2//! which need to traverse the BLAKE3 Merkle tree and work with chunk and parent
3//! chaining values directly. There might be breaking changes to this module
4//! between patch versions.
5//!
6//! We could stabilize something like this module in the future. If you have a
7//! use case for it, please let us know by filing a GitHub issue.
8
9pub const BLOCK_LEN: usize = 64;
10pub const CHUNK_LEN: usize = 1024;
11
12#[derive(Clone, Debug)]
13pub struct ChunkState(crate::ChunkState);
14
15impl ChunkState {
16    // Currently this type only supports the regular hash mode. If an
17    // incremental user needs keyed_hash or derive_key, we can add that.
18    pub fn new(chunk_counter: u64) -> Self {
19        Self(crate::ChunkState::new(
20            crate::IV,
21            chunk_counter,
22            0,
23            crate::platform::Platform::detect(),
24        ))
25    }
26
27    #[inline]
28    pub fn len(&self) -> usize {
29        self.0.len()
30    }
31
32    #[inline]
33    pub fn update(&mut self, input: &[u8]) -> &mut Self {
34        self.0.update(input);
35        self
36    }
37
38    pub fn finalize(&self, is_root: bool) -> crate::Hash {
39        let output = self.0.output();
40        if is_root {
41            output.root_hash()
42        } else {
43            output.chaining_value().into()
44        }
45    }
46}
47
48// As above, this currently assumes the regular hash mode. If an incremental
49// user needs keyed_hash or derive_key, we can add that.
50pub fn parent_cv(
51    left_child: &crate::Hash,
52    right_child: &crate::Hash,
53    is_root: bool,
54) -> crate::Hash {
55    let output = crate::parent_node_output(
56        left_child.as_bytes(),
57        right_child.as_bytes(),
58        crate::IV,
59        0,
60        crate::platform::Platform::detect(),
61    );
62    if is_root {
63        output.root_hash()
64    } else {
65        output.chaining_value().into()
66    }
67}
68
69#[cfg(test)]
70mod test {
71    use super::*;
72
73    #[test]
74    fn test_chunk() {
75        assert_eq!(
76            crate::hash(b"foo"),
77            ChunkState::new(0).update(b"foo").finalize(true)
78        );
79    }
80
81    #[test]
82    fn test_parents() {
83        let mut hasher = crate::Hasher::new();
84        let mut buf = [0; crate::CHUNK_LEN];
85
86        buf[0] = 'a' as u8;
87        hasher.update(&buf);
88        let chunk0_cv = ChunkState::new(0).update(&buf).finalize(false);
89
90        buf[0] = 'b' as u8;
91        hasher.update(&buf);
92        let chunk1_cv = ChunkState::new(1).update(&buf).finalize(false);
93
94        hasher.update(b"c");
95        let chunk2_cv = ChunkState::new(2).update(b"c").finalize(false);
96
97        let parent = parent_cv(&chunk0_cv, &chunk1_cv, false);
98        let root = parent_cv(&parent, &chunk2_cv, true);
99        assert_eq!(hasher.finalize(), root);
100    }
101}