Skip to main content

hash_many

Function hash_many 

Source
pub fn hash_many(input: &[u8], message_len: usize, out: &mut [[u8; 32]])
Expand description

The hashes of many messages of one length, laid out in one buffer, on the calling thread: out[i] becomes the hash of message i.

Message i starts at byte i * stride of input, where stride is message_len rounded up to a multiple of 64 (64 for empty messages), so messages whose length is a multiple of 64 sit back to back. input holds exactly out.len() strides, and the bytes between a message’s end and the next stride are zero (debug builds check; another byte there changes that message’s hash). This is the shape of a Merkle tree’s layer: leaves of one size, or nodes of two 32-byte children (message_len 64).

let leaves = vec![7u8; 1000 * 256];
let mut hashes = vec![[0u8; 32]; 1000];
blake3_servil::hash_many(&leaves, 256, &mut hashes);
assert_eq!(hashes[3], *blake3_servil::hash(&leaves[3 * 256..4 * 256]).as_bytes());

// 100-byte messages sit 128 bytes apart, zero between them.
let mut records = vec![0u8; 10 * 128];
for (i, record) in records.chunks_mut(128).enumerate() {
    record[..100].fill(i as u8 + 1);
}
let mut digests = vec![[0u8; 32]; 10];
blake3_servil::hash_many(&records, 100, &mut digests);
assert_eq!(digests[9], *blake3_servil::hash(&[10u8; 100]).as_bytes());

Speed: short messages hash several at a time, so a batch beats a loop of hash: on an Apple M4 Max, 64-byte messages take about 10 to 20 ns each in batches of 16 or more, against about 50 for one hash each. Messages longer than 15 KiB cost what hash costs. For the same hashes over several cores, see hash_many_multithreaded.