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
use crate::{bits_to_rate, keccakp::KeccakP, EncodedLen, Hasher, KeccakState};
fn encode_len(len: usize) -> EncodedLen {
let len_view = (len as u64).to_be_bytes();
let offset = len_view.iter().position(|i| *i != 0).unwrap_or(8);
let mut buffer = [0u8; 9];
buffer[..8].copy_from_slice(&len_view);
buffer[8] = 8 - offset as u8;
EncodedLen { offset, buffer }
}
#[derive(Clone)]
pub struct KangarooTwelve<T> {
state: KeccakState<KeccakP>,
current_chunk: KeccakState<KeccakP>,
custom_string: Option<T>,
written: usize,
chunks: usize,
}
impl<T> KangarooTwelve<T> {
const MAX_CHUNK_SIZE: usize = 8192;
pub fn new(custom_string: T) -> Self {
let rate = bits_to_rate(128);
KangarooTwelve {
state: KeccakState::new(rate, 0),
current_chunk: KeccakState::new(rate, 0x0b),
custom_string: Some(custom_string),
written: 0,
chunks: 0,
}
}
}
impl<T: AsRef<[u8]> + Clone> Hasher for KangarooTwelve<T> {
fn update(&mut self, input: &[u8]) {
let mut to_absorb = input;
if self.chunks == 0 {
let todo = core::cmp::min(Self::MAX_CHUNK_SIZE - self.written, to_absorb.len());
self.state.update(&to_absorb[..todo]);
self.written += todo;
to_absorb = &to_absorb[todo..];
if to_absorb.len() > 0 && self.written == Self::MAX_CHUNK_SIZE {
self.state.update(&[0x03, 0, 0, 0, 0, 0, 0, 0]);
self.written = 0;
self.chunks += 1;
}
}
while to_absorb.len() > 0 {
if self.written == Self::MAX_CHUNK_SIZE {
let mut chunk_hash = [0u8; 32];
let current_chunk = self.current_chunk.clone();
self.current_chunk.reset();
current_chunk.finalize(&mut chunk_hash);
self.state.update(&chunk_hash);
self.written = 0;
self.chunks += 1;
}
let todo = core::cmp::min(Self::MAX_CHUNK_SIZE - self.written, to_absorb.len());
self.current_chunk.update(&to_absorb[..todo]);
self.written += todo;
to_absorb = &to_absorb[todo..];
}
}
fn finalize(mut self, output: &mut [u8]) {
let custom_string = self
.custom_string
.take()
.expect("KangarooTwelve cannot be initialized without custom_string; qed");
let encoded_len = encode_len(custom_string.as_ref().len());
self.update(custom_string.as_ref());
self.update(encoded_len.value());
if self.chunks == 0 {
self.state.delim = 0x07;
} else {
let encoded_chunks = encode_len(self.chunks);
let mut tmp_chunk = [0u8; 32];
self.current_chunk.finalize(&mut tmp_chunk);
self.state.update(&tmp_chunk);
self.state.update(encoded_chunks.value());
self.state.update(&[0xff, 0xff]);
self.state.delim = 0x06;
}
self.state.finalize(output);
}
}