1#![no_std]
37#![doc(
38 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
39 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
40)]
41#![allow(clippy::undocumented_unsafe_blocks)] pub use hybrid_array as array;
44
45use array::{Array, ArraySize, typenum::Sum};
46use core::{fmt, mem::MaybeUninit, ptr, slice};
47
48#[cfg(feature = "zeroize")]
49use zeroize::{Zeroize, ZeroizeOnDrop};
50
51mod read;
52mod sealed;
53
54pub use read::ReadBuffer;
55
56pub trait BlockSizes: ArraySize + sealed::BlockSizes {}
58
59impl<T: ArraySize + sealed::BlockSizes> BlockSizes for T {}
60
61pub trait BufferKind: sealed::Sealed {}
63
64#[derive(Copy, Clone, Debug, Default)]
67pub struct Eager {}
68
69#[derive(Copy, Clone, Debug, Default)]
72pub struct Lazy {}
73
74impl BufferKind for Eager {}
75
76impl BufferKind for Lazy {}
77
78pub type EagerBuffer<B> = BlockBuffer<B, Eager>;
80pub type LazyBuffer<B> = BlockBuffer<B, Lazy>;
82
83#[derive(Copy, Clone, Eq, PartialEq, Debug)]
85pub struct Error;
86
87impl fmt::Display for Error {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
89 f.write_str("Block buffer error")
90 }
91}
92
93pub struct BlockBuffer<BS: BlockSizes, K: BufferKind> {
95 buffer: MaybeUninit<Array<u8, BS>>,
96 pos: K::Pos,
97}
98
99impl<BS: BlockSizes, K: BufferKind> Default for BlockBuffer<BS, K> {
100 #[inline]
101 fn default() -> Self {
102 let mut buffer = MaybeUninit::uninit();
103 let mut pos = Default::default();
104 K::set_pos(&mut buffer, &mut pos, 0);
105 Self { buffer, pos }
106 }
107}
108
109impl<BS: BlockSizes, K: BufferKind> Clone for BlockBuffer<BS, K> {
110 #[inline]
111 fn clone(&self) -> Self {
112 unsafe { ptr::read(self) }
115 }
116}
117
118impl<BS: BlockSizes, K: BufferKind> fmt::Debug for BlockBuffer<BS, K> {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
120 f.debug_struct(K::NAME)
121 .field("pos", &self.get_pos())
122 .field("block_size", &BS::USIZE)
123 .field("data", &self.get_data())
124 .finish()
125 }
126}
127
128impl<BS: BlockSizes, K: BufferKind> BlockBuffer<BS, K> {
129 #[inline(always)]
134 #[must_use]
135 #[track_caller]
136 pub fn new(buf: &[u8]) -> Self {
137 Self::try_new(buf).expect("invalid slice length for buffer kind")
138 }
139
140 #[inline(always)]
145 pub fn try_new(buf: &[u8]) -> Result<Self, Error> {
146 if !K::invariant(buf.len(), BS::USIZE) {
147 return Err(Error);
148 }
149 let mut res = Self::default();
150 unsafe {
152 res.set_data_unchecked(buf);
153 }
154 Ok(res)
155 }
156
157 #[inline]
160 pub fn digest_blocks(&mut self, mut input: &[u8], mut compress: impl FnMut(&[Array<u8, BS>])) {
161 let pos = self.get_pos();
162 let rem = self.size() - pos;
165 let n = input.len();
166 if K::invariant(n, rem) {
174 unsafe {
178 let buf_ptr = self.buffer.as_mut_ptr().cast::<u8>().add(pos);
179 ptr::copy_nonoverlapping(input.as_ptr(), buf_ptr, input.len());
180 self.set_pos_unchecked(pos + input.len());
181 }
182 return;
183 }
184 if pos != 0 {
185 let (left, right) = input.split_at(rem);
186 input = right;
187
188 let g = ResetGuard(self);
189 let buf = &mut g.0.buffer;
190 let block = unsafe {
196 let buf_ptr = buf.as_mut_ptr().cast::<u8>().add(pos);
197 ptr::copy_nonoverlapping(left.as_ptr(), buf_ptr, left.len());
198 buf.assume_init_ref()
199 };
200 compress(slice::from_ref(block));
201 }
202
203 let (blocks, leftover) = K::split_blocks(input);
204 if !blocks.is_empty() {
205 compress(blocks);
206 }
207
208 unsafe {
211 self.set_data_unchecked(leftover);
212 }
213 }
214
215 #[inline(always)]
217 pub fn reset(&mut self) {
218 unsafe {
220 self.set_pos_unchecked(0);
221 }
222 }
223
224 #[inline(always)]
226 pub fn pad_with_zeros(&mut self) -> Array<u8, BS> {
227 let mut res = Array::<u8, BS>::default();
228 let data = self.get_data();
229 res[..data.len()].copy_from_slice(data);
230 self.reset();
231 res
232 }
233
234 #[inline(always)]
236 pub fn get_pos(&self) -> usize {
237 let pos = K::get_pos(&self.buffer, &self.pos);
238 if !K::invariant(pos, BS::USIZE) {
239 debug_assert!(false);
240 unsafe {
242 core::hint::unreachable_unchecked();
243 }
244 }
245 pos
246 }
247
248 #[inline(always)]
250 pub fn get_data(&self) -> &[u8] {
251 unsafe { slice::from_raw_parts(self.buffer.as_ptr().cast(), self.get_pos()) }
254 }
255
256 #[inline]
261 pub fn set(&mut self, buf: Array<u8, BS>, pos: usize) {
262 assert!(K::invariant(pos, BS::USIZE));
263 self.buffer = MaybeUninit::new(buf);
264 unsafe {
267 self.set_pos_unchecked(pos);
268 }
269 }
270
271 #[inline(always)]
273 pub fn size(&self) -> usize {
274 BS::USIZE
275 }
276
277 #[inline(always)]
279 pub fn remaining(&self) -> usize {
280 self.size() - self.get_pos()
281 }
282
283 #[inline(always)]
292 unsafe fn set_pos_unchecked(&mut self, pos: usize) {
293 debug_assert!(K::invariant(pos, BS::USIZE));
294 K::set_pos(&mut self.buffer, &mut self.pos, pos);
295 }
296
297 #[inline(always)]
304 unsafe fn set_data_unchecked(&mut self, buf: &[u8]) {
305 unsafe {
306 self.set_pos_unchecked(buf.len());
307 let dst_ptr: *mut u8 = self.buffer.as_mut_ptr().cast();
308 ptr::copy_nonoverlapping(buf.as_ptr(), dst_ptr, buf.len());
309 }
310 }
311}
312
313pub type SerializedBufferSize<BS, K> = Sum<BS, <K as sealed::Sealed>::Overhead>;
315pub type SerializedBuffer<BS, K> = Array<u8, SerializedBufferSize<BS, K>>;
317
318impl<BS: BlockSizes, K: BufferKind> BlockBuffer<BS, K>
319where
320 BS: core::ops::Add<K::Overhead>,
321 Sum<BS, K::Overhead>: ArraySize,
322{
323 #[allow(clippy::missing_panics_doc)]
325 pub fn serialize(&self) -> SerializedBuffer<BS, K> {
326 let mut buf = SerializedBuffer::<BS, K>::default();
327 let data = self.get_data();
328 let (pos, block) = buf.split_at_mut(1);
329 pos[0] = u8::try_from(data.len()).expect("buffer size is smaller than 256");
330 block[..data.len()].copy_from_slice(data);
331 buf
332 }
333
334 pub fn deserialize(buf: &SerializedBuffer<BS, K>) -> Result<Self, Error> {
339 let (pos, block) = buf.split_at(1);
340 let pos = usize::from(pos[0]);
341
342 if !<K as sealed::Sealed>::invariant(pos, BS::USIZE) {
343 return Err(Error);
344 }
345
346 let (data, tail) = block.split_at(pos);
347
348 if tail.iter().any(|&b| b != 0) {
349 return Err(Error);
350 }
351
352 let mut res = Self::default();
353 unsafe { res.set_data_unchecked(data) };
354 Ok(res)
355 }
356}
357
358impl<BS: BlockSizes> BlockBuffer<BS, Eager> {
359 #[inline(always)]
366 pub fn digest_pad(
367 &mut self,
368 delim: u8,
369 suffix: &[u8],
370 mut compress: impl FnMut(&Array<u8, BS>),
371 ) {
372 let pos = self.get_pos();
373 let size = self.size();
374 let pad_len = size - pos - 1;
377
378 let suffix_dst_pos = size
379 .checked_sub(suffix.len())
380 .expect("suffix must be smaller than buffer block size");
381
382 let g = ResetGuard(self);
383 let buf = unsafe {
387 let p: *mut u8 = g.0.buffer.as_mut_ptr().cast::<u8>().add(pos);
388 ptr::write(p, delim);
389 ptr::write_bytes(p.add(1), 0, pad_len);
390 g.0.buffer.assume_init_mut()
391 };
392
393 if pad_len < suffix.len() {
394 compress(buf);
395 buf.fill(0);
396 }
397
398 buf[suffix_dst_pos..].copy_from_slice(suffix);
399 compress(buf);
400 }
401
402 #[inline]
405 pub fn len64_padding_be(&mut self, data_len: u64, compress: impl FnMut(&Array<u8, BS>)) {
406 self.digest_pad(0x80, &data_len.to_be_bytes(), compress);
407 }
408
409 #[inline]
412 pub fn len64_padding_le(&mut self, data_len: u64, compress: impl FnMut(&Array<u8, BS>)) {
413 self.digest_pad(0x80, &data_len.to_le_bytes(), compress);
414 }
415
416 #[inline]
419 pub fn len128_padding_be(&mut self, data_len: u128, compress: impl FnMut(&Array<u8, BS>)) {
420 self.digest_pad(0x80, &data_len.to_be_bytes(), compress);
421 }
422}
423
424#[cfg(feature = "zeroize")]
425impl<BS: BlockSizes, K: BufferKind> Zeroize for BlockBuffer<BS, K> {
426 #[inline]
427 fn zeroize(&mut self) {
428 self.buffer.zeroize();
429 self.pos.zeroize();
430 }
431}
432
433impl<BS: BlockSizes, K: BufferKind> Drop for BlockBuffer<BS, K> {
434 #[inline]
435 fn drop(&mut self) {
436 #[cfg(feature = "zeroize")]
437 self.zeroize();
438 }
439}
440
441#[cfg(feature = "zeroize")]
442impl<BS: BlockSizes, K: BufferKind> ZeroizeOnDrop for BlockBuffer<BS, K> {}
443
444struct ResetGuard<'a, BS: BlockSizes, K: BufferKind>(&'a mut BlockBuffer<BS, K>);
446
447impl<BS: BlockSizes, K: BufferKind> Drop for ResetGuard<'_, BS, K> {
448 fn drop(&mut self) {
449 self.0.reset();
450 }
451}