diff --git a/c/README.md b/c/README.md index e3fca0c..5e35fe0 100644 --- a/c/README.md +++ b/c/README.md @@ -185,6 +185,21 @@ parameter for the starting byte position in the output stream. To efficiently stream a large output without allocating memory, call this function in a loop, incrementing `seek` by the output length each time. +--- + +```c +void blake3_hasher_reset( + blake3_hasher *self); +``` + +Reset the hasher to its initial state, prior to any calls to +`blake3_hasher_update`. Currently this is no different from calling +`blake3_hasher_init` or similar again. However, if this implementation gains +multithreading support in the future, and if `blake3_hasher` holds (optional) +threading resources, this function will reuse those resources. Until then, this +is mainly for feature compatibility with the Rust implementation. + + # Building This implementation is just C and assembly files. It doesn't include a diff --git a/c/blake3.c b/c/blake3.c index 20b6bd0..1239433 100644 --- a/c/blake3.c +++ b/c/blake3.c @@ -609,3 +609,8 @@ void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, } output_root_bytes(&output, seek, out, out_len); } + +void blake3_hasher_reset(blake3_hasher *self) { + chunk_state_reset(&self->chunk, self->key, 0); + self->cv_stack_len = 0; +} diff --git a/c/blake3.h b/c/blake3.h index c3ca22d..5cccc90 100644 --- a/c/blake3.h +++ b/c/blake3.h @@ -51,6 +51,7 @@ void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, size_t out_len); void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len); +void blake3_hasher_reset(blake3_hasher *self); #ifdef __cplusplus } diff --git a/c/blake3_c_rust_bindings/src/lib.rs b/c/blake3_c_rust_bindings/src/lib.rs index f18fe12..41e4938 100644 --- a/c/blake3_c_rust_bindings/src/lib.rs +++ b/c/blake3_c_rust_bindings/src/lib.rs @@ -93,6 +93,12 @@ impl Hasher { ffi::blake3_hasher_finalize_seek(&self.0, seek, output.as_mut_ptr(), output.len()); } } + + pub fn reset(&mut self) { + unsafe { + ffi::blake3_hasher_reset(&mut self.0); + } + } } pub mod ffi { @@ -141,6 +147,7 @@ pub mod ffi { out: *mut u8, out_len: usize, ); + pub fn blake3_hasher_reset(self_: *mut blake3_hasher); // portable low-level functions pub fn blake3_compress_in_place_portable( diff --git a/c/blake3_c_rust_bindings/src/test.rs b/c/blake3_c_rust_bindings/src/test.rs index 3b3d8a7..f4d4810 100644 --- a/c/blake3_c_rust_bindings/src/test.rs +++ b/c/blake3_c_rust_bindings/src/test.rs @@ -509,3 +509,54 @@ fn test_finalize_seek() { assert_eq!(&expected[seek..][..out.len()], &out[..]); } } + +#[test] +fn test_reset() { + { + let mut hasher = crate::Hasher::new(); + hasher.update(&[42; 3 * CHUNK_LEN + 7]); + hasher.reset(); + hasher.update(&[42; CHUNK_LEN + 3]); + let mut output = [0; 32]; + hasher.finalize(&mut output); + + let mut reference_hasher = reference_impl::Hasher::new(); + reference_hasher.update(&[42; CHUNK_LEN + 3]); + let mut reference_hash = [0; 32]; + reference_hasher.finalize(&mut reference_hash); + + assert_eq!(reference_hash, output); + } + { + let key = &[99; 32]; + let mut hasher = crate::Hasher::new_keyed(key); + hasher.update(&[42; 3 * CHUNK_LEN + 7]); + hasher.reset(); + hasher.update(&[42; CHUNK_LEN + 3]); + let mut output = [0; 32]; + hasher.finalize(&mut output); + + let mut reference_hasher = reference_impl::Hasher::new_keyed(key); + reference_hasher.update(&[42; CHUNK_LEN + 3]); + let mut reference_hash = [0; 32]; + reference_hasher.finalize(&mut reference_hash); + + assert_eq!(reference_hash, output); + } + { + let context = "BLAKE3 2020-02-12 10:20:58 reset test"; + let mut hasher = crate::Hasher::new_derive_key(context); + hasher.update(&[42; 3 * CHUNK_LEN + 7]); + hasher.reset(); + hasher.update(&[42; CHUNK_LEN + 3]); + let mut output = [0; 32]; + hasher.finalize(&mut output); + + let mut reference_hasher = reference_impl::Hasher::new_derive_key(context); + reference_hasher.update(&[42; CHUNK_LEN + 3]); + let mut reference_hash = [0; 32]; + reference_hasher.finalize(&mut reference_hash); + + assert_eq!(reference_hash, output); + } +}