diff --git a/src/guts.rs b/src/guts.rs index ecde326..24ea414 100644 --- a/src/guts.rs +++ b/src/guts.rs @@ -9,6 +9,12 @@ pub const BLOCK_LEN: usize = 64; pub const CHUNK_LEN: usize = 1024; +pub fn hash_block(start_chunk: u64, data: &[u8], is_root: bool) -> crate::Hash { + let mut hasher = crate::Hasher::new_with_start_chunk(start_chunk); + hasher.update(data); + hasher.finalize_node(is_root) +} + #[derive(Clone, Debug)] pub struct ChunkState(crate::ChunkState); @@ -98,4 +104,12 @@ mod test { let root = parent_cv(&parent, &chunk2_cv, true); assert_eq!(hasher.finalize(), root); } + + #[test] + fn test_hash_block() { + assert_eq!( + crate::hash(b"foo"), + hash_block(0, b"foo", true) + ); + } } diff --git a/src/lib.rs b/src/lib.rs index e2a4d9c..71562f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -409,6 +409,18 @@ impl Output { Hash(platform::le_bytes_from_words_32(&cv)) } + fn hash(&self, is_root: bool) -> Hash { + // debug_assert_eq!(self.counter, 0); + let mut cv = self.input_chaining_value; + let mut flags = self.flags; + if is_root { + flags |= ROOT; + } + self.platform + .compress_in_place(&mut cv, &self.block, self.block_len, 0, flags); + Hash(platform::le_bytes_from_words_32(&cv)) + } + fn root_output_block(&self) -> [u8; 2 * OUT_LEN] { self.platform.compress_xof( &self.input_chaining_value, @@ -977,6 +989,15 @@ impl Hasher { Self::new_internal(IV, 0) } + /// Construct a new `Hasher` with a start chunk + fn new_with_start_chunk(start_chunk: u64) -> Self { + Self { + key: *IV, + chunk_state: ChunkState::new(IV, start_chunk, 0, Platform::detect()), + cv_stack: ArrayVec::new(), + } + } + /// Construct a new `Hasher` for the keyed hash function. See /// [`keyed_hash`]. /// @@ -1246,7 +1267,7 @@ impl Hasher { // also. Convert it directly into an Output. Otherwise, we need to // merge subtrees below. if self.cv_stack.is_empty() { - debug_assert_eq!(self.chunk_state.chunk_counter, 0); + // debug_assert_eq!(self.chunk_state.chunk_counter, 0); return self.chunk_state.output(); } @@ -1265,11 +1286,11 @@ impl Hasher { let mut output: Output; let mut num_cvs_remaining = self.cv_stack.len(); if self.chunk_state.len() > 0 { - debug_assert_eq!( - self.cv_stack.len(), - self.chunk_state.chunk_counter.count_ones() as usize, - "cv stack does not need a merge" - ); + // debug_assert_eq!( + // self.cv_stack.len(), + // self.chunk_state.chunk_counter.count_ones() as usize, + // "cv stack does not need a merge" + // ); output = self.chunk_state.output(); } else { debug_assert!(self.cv_stack.len() >= 2); @@ -1304,6 +1325,11 @@ impl Hasher { self.final_output().root_hash() } + fn finalize_node(&self, is_root: bool) -> Hash { + let output = self.final_output(); + output.hash(is_root) + } + /// Finalize the hash state and return an [`OutputReader`], which can /// supply any number of output bytes. ///