1use crate::{bits_to_rate, keccakp::KeccakP, EncodedLen, Hasher, IntoXof, KeccakState, Xof};
6
7fn encode_len(len: usize) -> EncodedLen {
8 let len_view = (len as u64).to_be_bytes();
9 let offset = len_view.iter().position(|i| *i != 0).unwrap_or(8);
10 let mut buffer = [0u8; 9];
11 buffer[..8].copy_from_slice(&len_view);
12 buffer[8] = 8 - offset as u8;
13
14 EncodedLen { offset, buffer }
15}
16
17#[derive(Clone)]
28pub struct KangarooTwelve<T> {
29 state: KeccakState<KeccakP>,
30 current_chunk: KeccakState<KeccakP>,
31 custom_string: Option<T>,
32 written: usize,
33 chunks: usize,
34}
35
36impl<T> KangarooTwelve<T> {
37 const MAX_CHUNK_SIZE: usize = 8192;
38
39 pub fn new(custom_string: T) -> Self {
43 let rate = bits_to_rate(128);
44 KangarooTwelve {
45 state: KeccakState::new(rate, 0),
46 current_chunk: KeccakState::new(rate, 0x0b),
47 custom_string: Some(custom_string),
48 written: 0,
49 chunks: 0,
50 }
51 }
52}
53
54impl<T: AsRef<[u8]>> Hasher for KangarooTwelve<T> {
55 fn update(&mut self, input: &[u8]) {
56 let mut to_absorb = input;
57 if self.chunks == 0 {
58 let todo = core::cmp::min(Self::MAX_CHUNK_SIZE - self.written, to_absorb.len());
59 self.state.update(&to_absorb[..todo]);
60 self.written += todo;
61 to_absorb = &to_absorb[todo..];
62
63 if to_absorb.len() > 0 && self.written == Self::MAX_CHUNK_SIZE {
64 self.state.update(&[0x03, 0, 0, 0, 0, 0, 0, 0]);
65 self.written = 0;
66 self.chunks += 1;
67 }
68 }
69
70 while to_absorb.len() > 0 {
71 if self.written == Self::MAX_CHUNK_SIZE {
72 let mut chunk_hash = [0u8; 32];
73 let current_chunk = self.current_chunk.clone();
74 self.current_chunk.reset();
75 current_chunk.finalize(&mut chunk_hash);
76 self.state.update(&chunk_hash);
77 self.written = 0;
78 self.chunks += 1;
79 }
80
81 let todo = core::cmp::min(Self::MAX_CHUNK_SIZE - self.written, to_absorb.len());
82 self.current_chunk.update(&to_absorb[..todo]);
83 self.written += todo;
84 to_absorb = &to_absorb[todo..];
85 }
86 }
87
88 fn finalize(self, output: &mut [u8]) {
89 let mut xof = self.into_xof();
90 xof.squeeze(output);
91 }
92}
93
94#[derive(Clone)]
124pub struct KangarooTwelveXof {
125 state: KeccakState<KeccakP>,
126}
127
128impl<T: AsRef<[u8]>> IntoXof for KangarooTwelve<T> {
129 type Xof = KangarooTwelveXof;
130
131 fn into_xof(mut self) -> KangarooTwelveXof {
132 let custom_string = self
133 .custom_string
134 .take()
135 .expect("KangarooTwelve cannot be initialized without custom_string; qed");
136 let encoded_len = encode_len(custom_string.as_ref().len());
137 self.update(custom_string.as_ref());
138 self.update(encoded_len.value());
139
140 if self.chunks == 0 {
141 self.state.delim = 0x07;
142 } else {
143 let encoded_chunks = encode_len(self.chunks);
144 let mut tmp_chunk = [0u8; 32];
145 self.current_chunk.finalize(&mut tmp_chunk);
146 self.state.update(&tmp_chunk);
147 self.state.update(encoded_chunks.value());
148 self.state.update(&[0xff, 0xff]);
149 self.state.delim = 0x06;
150 }
151
152 KangarooTwelveXof { state: self.state }
153 }
154}
155
156impl Xof for KangarooTwelveXof {
157 fn squeeze(&mut self, output: &mut [u8]) {
158 self.state.squeeze(output);
159 }
160}