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.