binius_hash/
serialization.rs1use std::{borrow::Borrow, cmp::min};
4
5use binius_utils::{SerializationMode, SerializeBytes};
6use bytes::{buf::UninitSlice, BufMut};
7use digest::{
8 core_api::{Block, BlockSizeUser},
9 Digest, Output,
10};
11
12#[derive(Debug)]
17pub struct HashBuffer<'a, D: Digest + BlockSizeUser> {
18 digest: &'a mut D,
19 block: Block<D>,
20 index: usize,
22}
23
24impl<'a, D: Digest + BlockSizeUser> HashBuffer<'a, D> {
25 pub fn new(digest: &'a mut D) -> Self {
26 Self {
27 digest,
28 block: <Block<D>>::default(),
29 index: 0,
30 }
31 }
32
33 fn flush(&mut self) {
34 self.digest.update(&self.block.as_slice()[..self.index]);
35 self.index = 0;
36 }
37}
38
39unsafe impl<D: Digest + BlockSizeUser> BufMut for HashBuffer<'_, D> {
40 fn remaining_mut(&self) -> usize {
41 usize::MAX
42 }
43
44 unsafe fn advance_mut(&mut self, mut cnt: usize) {
45 while cnt > 0 {
46 let remaining = min(<D as BlockSizeUser>::block_size() - self.index, cnt);
47 cnt -= remaining;
48 self.index += remaining;
49 if self.index == <D as BlockSizeUser>::block_size() {
50 self.flush();
51 }
52 }
53 }
54
55 fn chunk_mut(&mut self) -> &mut UninitSlice {
56 let buffer = &mut self.block[self.index..];
57 buffer.into()
58 }
59}
60
61impl<D: Digest + BlockSizeUser> Drop for HashBuffer<'_, D> {
62 fn drop(&mut self) {
63 self.flush()
64 }
65}
66
67pub fn hash_serialize<T, D>(items: impl IntoIterator<Item = impl Borrow<T>>) -> Output<D>
69where
70 T: SerializeBytes,
71 D: Digest + BlockSizeUser,
72{
73 let mut hasher = D::new();
74 {
75 let mut buffer = HashBuffer::new(&mut hasher);
76 for item in items {
77 item.borrow()
78 .serialize(&mut buffer, SerializationMode::CanonicalTower)
79 .expect("HashBuffer has infinite capacity");
80 }
81 }
82 hasher.finalize()
83}
84
85#[cfg(test)]
86mod tests {
87 use groestl_crypto::Groestl256;
88
89 use super::*;
90
91 #[test]
92 fn test_hash_buffer_updates() {
93 let message =
94 b"yo, listen up, here's the story about a little guy that lives in a blue world";
95 assert!(message.len() > 64);
96 assert!(message.len() < 128);
97
98 let expected_digest = Groestl256::digest(message);
99
100 let mut hasher = Groestl256::new();
101 {
102 let mut buffer = HashBuffer::new(&mut hasher);
103 buffer.put_slice(message);
104 }
105 assert_eq!(hasher.finalize(), expected_digest);
106 }
107}