2021-03-28 21:12:42 +02:00
|
|
|
//! 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.
|
2019-12-29 17:37:16 +01:00
|
|
|
|
2021-03-29 02:01:18 +02:00
|
|
|
pub const BLOCK_LEN: usize = 64;
|
|
|
|
pub const CHUNK_LEN: usize = 1024;
|
|
|
|
|
2019-12-29 17:37:16 +01:00
|
|
|
#[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(),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2020-01-11 17:04:25 +01:00
|
|
|
#[inline]
|
2019-12-29 17:37:16 +01:00
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.0.len()
|
|
|
|
}
|
|
|
|
|
2020-01-11 17:04:25 +01:00
|
|
|
#[inline]
|
2019-12-29 17:37:16 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|