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
use crate::{bits_to_rate, keccakp::KeccakP, EncodedLen, Hasher, IntoXof, KeccakState, Xof};
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]>> 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(self, output: &mut [u8]) {
let mut xof = self.into_xof();
xof.squeeze(output);
}
}
#[derive(Clone)]
pub struct KangarooTwelveXof {
state: KeccakState<KeccakP>,
}
impl<T: AsRef<[u8]>> IntoXof for KangarooTwelve<T> {
type Xof = KangarooTwelveXof;
fn into_xof(mut self) -> KangarooTwelveXof {
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;
}
KangarooTwelveXof { state: self.state }
}
}
impl Xof for KangarooTwelveXof {
fn squeeze(&mut self, output: &mut [u8]) {
self.state.squeeze(output);
}
}