binius_hash/
serialization.rs1use std::{borrow::Borrow, cmp::min};
4
5use binius_utils::{SerializationError, SerializationMode, SerializeBytes};
6use bytes::{BufMut, buf::UninitSlice};
7use digest::{
8 Digest, Output,
9 core_api::{Block, BlockSizeUser},
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>(
69 items: impl IntoIterator<Item = impl Borrow<T>>,
70) -> Result<Output<D>, SerializationError>
71where
72 T: SerializeBytes,
73 D: Digest + BlockSizeUser,
74{
75 let mut hasher = D::new();
76 {
77 let mut buffer = HashBuffer::new(&mut hasher);
78 for item in items {
79 item.borrow()
80 .serialize(&mut buffer, SerializationMode::CanonicalTower)?;
81 }
82 }
83 Ok(hasher.finalize())
84}
85
86#[cfg(test)]
87mod tests {
88 use groestl_crypto::Groestl256;
89
90 use super::*;
91
92 #[test]
93 fn test_hash_buffer_updates() {
94 let message =
95 b"yo, listen up, here's the story about a little guy that lives in a blue world";
96 assert!(message.len() > 64);
97 assert!(message.len() < 128);
98
99 let expected_digest = Groestl256::digest(message);
100
101 let mut hasher = Groestl256::new();
102 {
103 let mut buffer = HashBuffer::new(&mut hasher);
104 buffer.put_slice(message);
105 }
106 assert_eq!(hasher.finalize(), expected_digest);
107 }
108}