mirror of
https://github.com/BLAKE3-team/BLAKE3
synced 2024-05-04 10:56:08 +02:00
add blake3_hasher_finalize_seek to the C API
This commit is contained in:
parent
4feadee6bb
commit
a4ceef3932
22
c/blake3.c
22
c/blake3.c
|
@ -84,23 +84,26 @@ INLINE void output_chaining_value(const output_t *self, uint8_t cv[32]) {
|
|||
memcpy(cv, cv_words, 32);
|
||||
}
|
||||
|
||||
INLINE void output_root_bytes(const output_t *self, uint8_t *out,
|
||||
INLINE void output_root_bytes(const output_t *self, uint64_t seek, uint8_t *out,
|
||||
size_t out_len) {
|
||||
uint64_t output_block_counter = 0;
|
||||
uint64_t output_block_counter = seek / 64;
|
||||
size_t offset_within_block = seek % 64;
|
||||
uint8_t wide_buf[64];
|
||||
while (out_len > 0) {
|
||||
blake3_compress_xof(self->input_cv, self->block, self->block_len,
|
||||
output_block_counter, self->flags | ROOT, wide_buf);
|
||||
size_t available_bytes = 64 - offset_within_block;
|
||||
size_t memcpy_len;
|
||||
if (out_len > 64) {
|
||||
memcpy_len = 64;
|
||||
if (out_len > available_bytes) {
|
||||
memcpy_len = available_bytes;
|
||||
} else {
|
||||
memcpy_len = out_len;
|
||||
}
|
||||
memcpy(out, wide_buf, memcpy_len);
|
||||
memcpy(out, wide_buf + offset_within_block, memcpy_len);
|
||||
out += memcpy_len;
|
||||
out_len -= memcpy_len;
|
||||
output_block_counter += 1;
|
||||
offset_within_block = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,6 +549,11 @@ void blake3_hasher_update(blake3_hasher *self, const void *input,
|
|||
|
||||
void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out,
|
||||
size_t out_len) {
|
||||
blake3_hasher_finalize_seek(self, 0, out, out_len);
|
||||
}
|
||||
|
||||
void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek,
|
||||
uint8_t *out, size_t out_len) {
|
||||
// Explicitly checking for zero avoids causing UB by passing a null pointer
|
||||
// to memcpy. This comes up in practice with things like:
|
||||
// std::vector<uint8_t> v;
|
||||
|
@ -557,7 +565,7 @@ void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out,
|
|||
// If the subtree stack is empty, then the current chunk is the root.
|
||||
if (self->cv_stack_len == 0) {
|
||||
output_t output = chunk_state_output(&self->chunk);
|
||||
output_root_bytes(&output, out, out_len);
|
||||
output_root_bytes(&output, seek, out, out_len);
|
||||
return;
|
||||
}
|
||||
// If there are any bytes in the chunk state, finalize that chunk and do a
|
||||
|
@ -585,5 +593,5 @@ void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out,
|
|||
output_chaining_value(&output, &parent_block[32]);
|
||||
output = parent_output(parent_block, self->key, self->chunk.flags);
|
||||
}
|
||||
output_root_bytes(&output, out, out_len);
|
||||
output_root_bytes(&output, seek, out, out_len);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -46,8 +46,10 @@ void blake3_hasher_update(blake3_hasher *self, const void *input,
|
|||
size_t input_len);
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -70,6 +70,12 @@ impl Hasher {
|
|||
ffi::blake3_hasher_finalize(&self.0, output.as_mut_ptr(), output.len());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finalize_seek(&self, seek: u64, output: &mut [u8]) {
|
||||
unsafe {
|
||||
ffi::blake3_hasher_finalize_seek(&self.0, seek, output.as_mut_ptr(), output.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod ffi {
|
||||
|
@ -107,6 +113,12 @@ pub mod ffi {
|
|||
input_len: usize,
|
||||
);
|
||||
pub fn blake3_hasher_finalize(self_: *const blake3_hasher, out: *mut u8, out_len: usize);
|
||||
pub fn blake3_hasher_finalize_seek(
|
||||
self_: *const blake3_hasher,
|
||||
seek: u64,
|
||||
out: *mut u8,
|
||||
out_len: usize,
|
||||
);
|
||||
|
||||
// portable low-level functions
|
||||
pub fn blake3_compress_in_place_portable(
|
||||
|
|
|
@ -444,3 +444,23 @@ fn test_fuzz_hasher() {
|
|||
assert_eq!(expected, test_out);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finalize_seek() {
|
||||
let mut expected = [0; 1000];
|
||||
{
|
||||
let mut reference_hasher = reference_impl::Hasher::new();
|
||||
reference_hasher.update(b"foobarbaz");
|
||||
reference_hasher.finalize(&mut expected);
|
||||
}
|
||||
|
||||
let mut test_hasher = crate::Hasher::new();
|
||||
test_hasher.update(b"foobarbaz");
|
||||
|
||||
let mut out = [0; 103];
|
||||
for &seek in &[0, 1, 7, 59, 63, 64, 65, 501, expected.len() - out.len()] {
|
||||
dbg!(seek);
|
||||
test_hasher.finalize_seek(seek as u64, &mut out);
|
||||
assert_eq!(&expected[seek..][..out.len()], &out[..]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue