mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-19 22:08:30 +00:00
Create cached_tree_hash crate.
This commit is contained in:
78
eth2/utils/cached_tree_hash/src/merkleize.rs
Normal file
78
eth2/utils/cached_tree_hash/src/merkleize.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
use hashing::hash;
|
||||
use tree_hash::{BYTES_PER_CHUNK, HASHSIZE, MERKLE_HASH_CHUNK};
|
||||
|
||||
/// Split `values` into a power-of-two, identical-length chunks (padding with `0`) and merkleize
|
||||
/// them, returning the entire merkle tree.
|
||||
///
|
||||
/// The root hash is `merkleize(values)[0..BYTES_PER_CHUNK]`.
|
||||
pub fn merkleize(values: Vec<u8>) -> Vec<u8> {
|
||||
let values = sanitise_bytes(values);
|
||||
|
||||
let leaves = values.len() / HASHSIZE;
|
||||
|
||||
if leaves == 0 {
|
||||
panic!("No full leaves");
|
||||
}
|
||||
|
||||
if !leaves.is_power_of_two() {
|
||||
panic!("leaves is not power of two");
|
||||
}
|
||||
|
||||
let mut o: Vec<u8> = vec![0; (num_nodes(leaves) - leaves) * HASHSIZE];
|
||||
o.append(&mut values.to_vec());
|
||||
|
||||
let mut i = o.len();
|
||||
let mut j = o.len() - values.len();
|
||||
|
||||
while i >= MERKLE_HASH_CHUNK {
|
||||
i -= MERKLE_HASH_CHUNK;
|
||||
let hash = hash(&o[i..i + MERKLE_HASH_CHUNK]);
|
||||
|
||||
j -= HASHSIZE;
|
||||
o[j..j + HASHSIZE].copy_from_slice(&hash);
|
||||
}
|
||||
|
||||
o
|
||||
}
|
||||
|
||||
pub fn sanitise_bytes(mut bytes: Vec<u8>) -> Vec<u8> {
|
||||
let present_leaves = num_unsanitized_leaves(bytes.len());
|
||||
let required_leaves = present_leaves.next_power_of_two();
|
||||
|
||||
if (present_leaves != required_leaves) | last_leaf_needs_padding(bytes.len()) {
|
||||
bytes.resize(num_bytes(required_leaves), 0);
|
||||
}
|
||||
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn pad_for_leaf_count(num_leaves: usize, bytes: &mut Vec<u8>) {
|
||||
let required_leaves = num_leaves.next_power_of_two();
|
||||
|
||||
bytes.resize(
|
||||
bytes.len() + (required_leaves - num_leaves) * BYTES_PER_CHUNK,
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
fn last_leaf_needs_padding(num_bytes: usize) -> bool {
|
||||
num_bytes % HASHSIZE != 0
|
||||
}
|
||||
|
||||
/// Rounds up
|
||||
fn num_unsanitized_leaves(num_bytes: usize) -> usize {
|
||||
(num_bytes + HASHSIZE - 1) / HASHSIZE
|
||||
}
|
||||
|
||||
fn num_bytes(num_leaves: usize) -> usize {
|
||||
num_leaves * HASHSIZE
|
||||
}
|
||||
|
||||
fn num_nodes(num_leaves: usize) -> usize {
|
||||
2 * num_leaves - 1
|
||||
}
|
||||
|
||||
pub fn num_sanitized_leaves(num_bytes: usize) -> usize {
|
||||
let leaves = (num_bytes + HASHSIZE - 1) / HASHSIZE;
|
||||
leaves.next_power_of_two()
|
||||
}
|
||||
Reference in New Issue
Block a user