//! This undocumented and unstable module is for use cases like the `bao` crate, //! which need to traverse the BLAKE3 Merkle tree and work with chunk and parent //! chaining values directly. There might be breaking changes to this module //! between patch versions. //! //! We could stabilize something like this module in the future. If you have a //! use case for it, please let us know by filing a GitHub issue. pub const BLOCK_LEN: usize = 64; pub const CHUNK_LEN: usize = 1024; #[derive(Clone, Debug)] pub struct ChunkState(crate::ChunkState); impl ChunkState { // Currently this type only supports the regular hash mode. If an // incremental user needs keyed_hash or derive_key, we can add that. pub fn new(chunk_counter: u64) -> Self { Self(crate::ChunkState::new( crate::IV, chunk_counter, 0, crate::platform::Platform::detect(), )) } #[inline] pub fn len(&self) -> usize { self.0.len() } #[inline] pub fn update(&mut self, input: &[u8]) -> &mut Self { self.0.update(input); self } pub fn finalize(&self, is_root: bool) -> crate::Hash { let output = self.0.output(); if is_root { output.root_hash() } else { output.chaining_value().into() } } } // As above, this currently assumes the regular hash mode. If an incremental // user needs keyed_hash or derive_key, we can add that. pub fn parent_cv( left_child: &crate::Hash, right_child: &crate::Hash, is_root: bool, ) -> crate::Hash { let output = crate::parent_node_output( left_child.as_bytes(), right_child.as_bytes(), crate::IV, 0, crate::platform::Platform::detect(), ); if is_root { output.root_hash() } else { output.chaining_value().into() } } #[cfg(test)] mod test { use super::*; #[test] fn test_chunk() { assert_eq!( crate::hash(b"foo"), ChunkState::new(0).update(b"foo").finalize(true) ); } #[test] fn test_parents() { let mut hasher = crate::Hasher::new(); let mut buf = [0; crate::CHUNK_LEN]; buf[0] = 'a' as u8; hasher.update(&buf); let chunk0_cv = ChunkState::new(0).update(&buf).finalize(false); buf[0] = 'b' as u8; hasher.update(&buf); let chunk1_cv = ChunkState::new(1).update(&buf).finalize(false); hasher.update(b"c"); let chunk2_cv = ChunkState::new(2).update(b"c").finalize(false); let parent = parent_cv(&chunk0_cv, &chunk1_cv, false); let root = parent_cv(&parent, &chunk2_cv, true); assert_eq!(hasher.finalize(), root); } }