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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use digest::Digest;
use blake2::Blake2s;
const DEFAULT_HASH_SIZE: usize = 32;
const DEFAULT_HASH_COUNT: usize = 65536;
pub struct Blakeout {
buffer: Vec<u8>,
result: Vec<u8>,
dirty: bool,
}
impl Default for Blakeout {
fn default() -> Self {
Blakeout::new()
}
}
impl Blakeout {
pub fn new() -> Self {
let mut buffer = Vec::new();
buffer.resize(DEFAULT_HASH_SIZE * DEFAULT_HASH_COUNT, 0u8);
Blakeout { buffer, result: Vec::new(), dirty: false }
}
pub fn update(&mut self, data: impl AsRef<[u8]>) {
self.process_input(data.as_ref());
}
pub fn reset(&mut self) {
self.dirty = false;
}
pub fn output_size() -> usize {
DEFAULT_HASH_SIZE
}
pub fn result(&self) -> &[u8] {
&self.result
}
pub fn result_str(&self) -> String {
to_hex(&self.result)
}
fn process_input(&mut self, data: &[u8]) {
let hash_size = DEFAULT_HASH_SIZE;
let hash_count = self.buffer.len() / hash_size;
let mut digest = Blake2s::default();
if self.dirty {
digest.update(&self.result);
}
digest.update(data);
Self::finalize_to(digest, &mut self.buffer.as_mut_slice()[0..hash_size]);
let double_size = hash_size * 2;
for x in (hash_size..hash_size * hash_count).step_by(hash_size) {
let mut digest = Blake2s::default();
let start = if x >= double_size { x - double_size } else { 0 };
digest.update(&self.buffer[start..x]);
Self::finalize_to(digest, &mut self.buffer.as_mut_slice()[x..(x + hash_size)]);
}
let mut digest = Blake2s::default();
digest.update(&self.buffer);
self.buffer.reverse();
digest.update(&self.buffer);
self.result.resize(DEFAULT_HASH_SIZE, 0u8);
Self::finalize_to(digest, self.result.as_mut_slice());
self.dirty = true;
}
fn finalize_to(digest: Blake2s, slice: &mut[u8]) {
let buf = Digest::finalize(digest);
slice.copy_from_slice(&buf[..]);
}
}
fn to_hex(buf: &[u8]) -> String {
let mut result = String::new();
for x in buf.iter() {
result.push_str(&format!("{:01$x}", x, 2));
}
result
}
#[cfg(test)]
mod tests {
use crate::{Blakeout, to_hex};
const DATA: &[u8; 29] = b"Science is poetry of reality!";
#[test]
fn single_input() {
let mut digest = Blakeout::default();
digest.update(DATA);
assert_eq!("4be892daff5d5432b43bf05c9d2ea4769daf2dd1ec482c23839ce5d6950e9e62", to_hex(&digest.result()));
}
#[test]
fn double_input() {
let mut digest = Blakeout::default();
digest.update(DATA);
digest.update(DATA);
assert_eq!("a1b6cd16c9e718b876afb7bf4d61b64291a98a3dea0f20731da663b0358e68b9", to_hex(&digest.result()));
}
#[test]
fn test_reset() {
let mut digest = Blakeout::default();
digest.update(DATA);
let hash1 = digest.result_str();
digest.reset();
digest.update(DATA);
let hash2 = digest.result_str();
assert_eq!(hash1, hash2);
}
}