1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::{utils::to_blocks, Block, DigestBuffer};
use generic_array::ArrayLength;
#[derive(Clone, Default)]
pub struct LazyBlockBuffer<BlockSize: ArrayLength<u8>> {
buffer: Block<BlockSize>,
pos: usize,
}
impl<BlockSize: ArrayLength<u8>> LazyBlockBuffer<BlockSize> {
pub fn pad_zeros(&mut self) -> &mut Block<BlockSize> {
let pos = self.get_pos();
self.buffer[pos..].iter_mut().for_each(|b| *b = 0);
self.set_pos_unchecked(0);
&mut self.buffer
}
#[inline]
pub fn size(&self) -> usize {
BlockSize::USIZE
}
#[inline]
pub fn remaining(&self) -> usize {
self.size() - self.get_pos()
}
#[inline]
pub fn reset(&mut self) {
self.pos = 0
}
#[inline]
pub fn get_pos(&self) -> usize {
debug_assert!(self.pos <= BlockSize::USIZE);
if self.pos > BlockSize::USIZE {
unsafe { core::hint::unreachable_unchecked() }
}
self.pos
}
pub fn set(&mut self, buf: Block<BlockSize>, pos: usize) {
assert!(pos <= BlockSize::USIZE);
self.buffer = buf;
self.pos = pos;
}
#[inline]
fn set_pos_unchecked(&mut self, pos: usize) {
debug_assert!(pos <= BlockSize::USIZE);
self.pos = pos;
}
}
impl<B: ArrayLength<u8>> DigestBuffer<B> for LazyBlockBuffer<B> {
#[inline]
fn digest_blocks(&mut self, mut input: &[u8], mut compress: impl FnMut(&[Block<B>])) {
let pos = self.get_pos();
let r = self.remaining();
let n = input.len();
if n <= r {
self.buffer[pos..][..n].copy_from_slice(input);
self.set_pos_unchecked(pos + n);
return;
}
if pos != 0 {
let (left, right) = input.split_at(r);
input = right;
self.buffer[pos..].copy_from_slice(left);
compress(core::slice::from_ref(&self.buffer));
}
let (mut blocks, mut leftover) = to_blocks(input);
if leftover.is_empty() {
debug_assert!(!blocks.is_empty());
let m = blocks.len() - 1;
unsafe {
leftover = blocks.get_unchecked(m);
blocks = blocks.get_unchecked(..m);
}
}
compress(blocks);
let n = leftover.len();
self.buffer[..n].copy_from_slice(leftover);
self.set_pos_unchecked(n);
}
#[inline]
fn reset(&mut self) {
self.pos = 0;
}
}