1#![no_std]
7#![doc(
8 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
9 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
10)]
11#![forbid(unsafe_code)]
12#![warn(missing_docs, rust_2018_idioms)]
13
14pub use digest;
15
16use core::fmt;
17use digest::block_buffer::Eager;
18use digest::consts::{U128, U168};
19use digest::core_api::{
20 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper, ExtendableOutputCore,
21 UpdateCore, XofReaderCore, XofReaderCoreWrapper,
22};
23use digest::{ExtendableOutputReset, HashMarker, Reset, Update, XofReader};
24
25use sha3::{TurboShake128, TurboShake128Core, TurboShake128ReaderCore};
26
27const CHUNK_SIZE: usize = 8192;
28const CHAINING_VALUE_SIZE: usize = 32;
29const LENGTH_ENCODE_SIZE: usize = 255;
30
31#[derive(Clone)]
33#[allow(non_camel_case_types)]
34pub struct KangarooTwelveCore<'cs> {
35 customization: &'cs [u8],
36 buffer: [u8; CHUNK_SIZE],
37 bufpos: usize,
38 final_tshk: TurboShake128,
39 chain_tshk: TurboShake128,
40 chain_length: usize,
41}
42
43impl<'cs> KangarooTwelveCore<'cs> {
44 pub fn new(customization: &'cs [u8]) -> Self {
46 Self {
47 customization,
48 buffer: [0u8; CHUNK_SIZE],
49 bufpos: 0usize,
50 final_tshk: TurboShake128::from_core(<TurboShake128Core>::new(0x06)),
51 chain_tshk: TurboShake128::from_core(<TurboShake128Core>::new(0x0B)),
52 chain_length: 0usize,
53 }
54 }
55}
56
57impl HashMarker for KangarooTwelveCore<'_> {}
58
59impl BlockSizeUser for KangarooTwelveCore<'_> {
60 type BlockSize = U128;
61}
62
63impl BufferKindUser for KangarooTwelveCore<'_> {
64 type BufferKind = Eager;
65}
66
67impl UpdateCore for KangarooTwelveCore<'_> {
68 #[inline]
69 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
70 for block in blocks {
71 self.buffer[self.bufpos..self.bufpos + 128].clone_from_slice(block);
72 self.bufpos += 128;
73
74 if self.bufpos != CHUNK_SIZE {
75 continue;
76 }
77
78 if self.chain_length == 0 {
79 self.final_tshk.update(&self.buffer);
80 self.final_tshk
81 .update(&[0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
82 } else {
83 let mut result = [0u8; CHAINING_VALUE_SIZE];
84 self.chain_tshk.update(&self.buffer);
85 self.chain_tshk.finalize_xof_reset_into(&mut result);
86 self.final_tshk.update(&result);
87 }
88
89 self.chain_length += 1;
90 self.buffer = [0u8; CHUNK_SIZE];
91 self.bufpos = 0;
92 }
93 }
94}
95
96impl ExtendableOutputCore for KangarooTwelveCore<'_> {
97 type ReaderCore = KangarooTwelveReaderCore;
98
99 #[inline]
100 fn finalize_xof_core(&mut self, buffer: &mut Buffer<Self>) -> Self::ReaderCore {
101 let mut lenbuf = [0u8; LENGTH_ENCODE_SIZE];
102
103 buffer.digest_blocks(self.customization, |block| self.update_blocks(block));
105 buffer.digest_blocks(
106 length_encode(self.customization.len(), &mut lenbuf),
107 |block| self.update_blocks(block),
108 );
109
110 self.buffer[self.bufpos..(self.bufpos + buffer.get_pos())]
112 .copy_from_slice(buffer.get_data());
113 self.bufpos += buffer.get_pos();
114
115 if self.chain_length == 0 {
117 let tshk = TurboShake128::from_core(<TurboShake128Core>::new(0x07))
119 .chain(&self.buffer[..self.bufpos])
120 .finalize_xof_reset();
121 return KangarooTwelveReaderCore { tshk };
122 }
123 let mut result = [0u8; CHAINING_VALUE_SIZE];
125 self.chain_tshk.update(&self.buffer[..self.bufpos]);
126 self.chain_tshk.finalize_xof_reset_into(&mut result);
127 self.final_tshk.update(&result);
128 self.final_tshk
130 .update(length_encode(self.chain_length, &mut lenbuf));
131 self.final_tshk.update(&[0xff, 0xff]);
132
133 KangarooTwelveReaderCore {
134 tshk: self.final_tshk.finalize_xof_reset(),
135 }
136 }
137}
138
139impl Default for KangarooTwelveCore<'_> {
140 #[inline]
141 fn default() -> Self {
142 Self {
143 customization: &[],
144 buffer: [0u8; CHUNK_SIZE],
145 bufpos: 0usize,
146 final_tshk: TurboShake128::from_core(<TurboShake128Core>::new(0x06)),
147 chain_tshk: TurboShake128::from_core(<TurboShake128Core>::new(0x0B)),
148 chain_length: 0usize,
149 }
150 }
151}
152
153impl Reset for KangarooTwelveCore<'_> {
154 #[inline]
155 fn reset(&mut self) {
156 *self = Self::new(self.customization);
157 }
158}
159
160impl AlgorithmName for KangarooTwelveCore<'_> {
161 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 f.write_str(stringify!(KangarooTwelve))
163 }
164}
165
166impl fmt::Debug for KangarooTwelveCore<'_> {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 f.write_str(concat!(stringify!(KangarooTwelveCore), " { ... }"))
169 }
170}
171
172#[derive(Clone)]
174#[allow(non_camel_case_types)]
175pub struct KangarooTwelveReaderCore {
176 tshk: XofReaderCoreWrapper<TurboShake128ReaderCore>,
177}
178
179impl BlockSizeUser for KangarooTwelveReaderCore {
180 type BlockSize = U168; }
182
183impl XofReaderCore for KangarooTwelveReaderCore {
184 #[inline]
185 fn read_block(&mut self) -> Block<Self> {
186 let mut block = Block::<Self>::default();
187 self.tshk.read(&mut block);
188 block
189 }
190}
191
192pub type KangarooTwelve<'cs> = CoreWrapper<KangarooTwelveCore<'cs>>;
194
195pub type KangarooTwelveReader = XofReaderCoreWrapper<KangarooTwelveReaderCore>;
197
198fn length_encode(mut length: usize, buffer: &mut [u8; LENGTH_ENCODE_SIZE]) -> &mut [u8] {
199 let mut bufpos = 0usize;
200 while length > 0 {
201 buffer[bufpos] = (length % 256) as u8;
202 length /= 256;
203 bufpos += 1;
204 }
205 buffer[..bufpos].reverse();
206
207 buffer[bufpos] = bufpos as u8;
208 bufpos += 1;
209
210 &mut buffer[..bufpos]
211}
212
213#[test]
214fn test_length_encode() {
215 let mut buffer = [0u8; LENGTH_ENCODE_SIZE];
216 assert_eq!(length_encode(0, &mut buffer), &[0x00]);
217 assert_eq!(length_encode(12, &mut buffer), &[0x0C, 0x01]);
218 assert_eq!(length_encode(65538, &mut buffer), &[0x01, 0x00, 0x02, 0x03]);
219}