tiny_keccak/
parallel_hash.rs1use crate::{left_encode, right_encode, CShake, Hasher, IntoXof, Xof};
2
3#[derive(Clone)]
4struct UnfinishedState {
5 state: CShake,
6 absorbed: usize,
7}
8
9struct Suboutout {
10 state: [u8; 64],
11 size: usize,
12}
13
14impl Suboutout {
15 fn security(bits: usize) -> Suboutout {
16 Suboutout {
17 state: [0u8; 64],
18 size: bits / 4,
20 }
21 }
22
23 #[inline]
24 fn as_bytes(&self) -> &[u8] {
25 &self.state[..self.size]
26 }
27
28 #[inline]
29 fn as_bytes_mut(&mut self) -> &mut [u8] {
30 &mut self.state[..self.size]
31 }
32}
33
34#[derive(Clone)]
51pub struct ParallelHash {
52 state: CShake,
53 block_size: usize,
54 bits: usize,
55 blocks: usize,
56 unfinished: Option<UnfinishedState>,
57}
58
59impl ParallelHash {
60 pub fn v128(custom_string: &[u8], block_size: usize) -> ParallelHash {
64 ParallelHash::new(custom_string, block_size, 128)
65 }
66
67 pub fn v256(custom_string: &[u8], block_size: usize) -> ParallelHash {
71 ParallelHash::new(custom_string, block_size, 256)
72 }
73
74 fn new(custom_string: &[u8], block_size: usize, bits: usize) -> ParallelHash {
75 let mut state = CShake::new(b"ParallelHash", custom_string, bits);
76 state.update(left_encode(block_size).value());
77 ParallelHash {
78 state,
79 block_size,
80 bits,
81 blocks: 0,
82 unfinished: None,
83 }
84 }
85}
86
87impl Hasher for ParallelHash {
88 fn update(&mut self, mut input: &[u8]) {
89 if let Some(mut unfinished) = self.unfinished.take() {
90 let to_absorb = self.block_size - unfinished.absorbed;
91 if input.len() >= to_absorb {
92 unfinished.state.update(&input[..to_absorb]);
93 input = &input[to_absorb..];
94
95 let mut suboutput = Suboutout::security(self.bits);
96 unfinished.state.finalize(suboutput.as_bytes_mut());
97 self.state.update(suboutput.as_bytes());
98 self.blocks += 1;
99 } else {
100 unfinished.state.update(input);
101 unfinished.absorbed += input.len();
102 self.unfinished = Some(unfinished);
103 return;
104 }
105 }
106
107 let bits = self.bits;
108 let input_blocks_end = input.len() / self.block_size * self.block_size;
109 let input_blocks = &input[..input_blocks_end];
110 let input_end = &input[input_blocks_end..];
111 let parts = input_blocks.chunks(self.block_size).map(|chunk| {
112 let mut state = CShake::new(b"", b"", bits);
113 state.update(chunk);
114 let mut suboutput = Suboutout::security(bits);
115 state.finalize(suboutput.as_bytes_mut());
116 suboutput
117 });
118
119 for part in parts {
120 self.state.update(part.as_bytes());
121 self.blocks += 1;
122 }
123
124 if !input_end.is_empty() {
125 assert!(self.unfinished.is_none());
126 let mut state = CShake::new(b"", b"", bits);
127 state.update(input_end);
128 self.unfinished = Some(UnfinishedState {
129 state,
130 absorbed: input_end.len(),
131 });
132 }
133 }
134
135 fn finalize(mut self, output: &mut [u8]) {
136 if let Some(unfinished) = self.unfinished.take() {
137 let mut suboutput = Suboutout::security(self.bits);
138 unfinished.state.finalize(suboutput.as_bytes_mut());
139 self.state.update(suboutput.as_bytes());
140 self.blocks += 1;
141 }
142
143 self.state.update(right_encode(self.blocks).value());
144 self.state.update(right_encode(output.len() * 8).value());
145 self.state.finalize(output);
146 }
147}
148
149#[derive(Clone)]
180pub struct ParallelHashXof {
181 state: CShake,
182}
183
184impl IntoXof for ParallelHash {
185 type Xof = ParallelHashXof;
186
187 fn into_xof(mut self) -> Self::Xof {
188 if let Some(unfinished) = self.unfinished.take() {
189 let mut suboutput = Suboutout::security(self.bits);
190 unfinished.state.finalize(suboutput.as_bytes_mut());
191 self.state.update(suboutput.as_bytes());
192 self.blocks += 1;
193 }
194
195 self.state.update(right_encode(self.blocks).value());
196 self.state.update(right_encode(0).value());
197
198 ParallelHashXof { state: self.state }
199 }
200}
201
202impl Xof for ParallelHashXof {
203 fn squeeze(&mut self, output: &mut [u8]) {
204 self.state.squeeze(output);
205 }
206}