tiny_keccak/
lib.rs

1//! Keccak derived functions specified in [`FIPS-202`], [`SP800-185`] and [`KangarooTwelve`].
2//!
3//! # Example
4//!
5//! ```
6//! # use tiny_keccak::Hasher;
7//! #
8//! # fn foo<H: Hasher>(mut hasher: H) {
9//! let input_a = b"hello world";
10//! let input_b = b"!";
11//! let mut output = [0u8; 32];
12//! hasher.update(input_a);
13//! hasher.update(input_b);
14//! hasher.finalize(&mut output);
15//! # }
16//! ```
17//!
18//! # Credits
19//!
20//! - [`coruus/keccak-tiny`] for C implementation of keccak function
21//! - [`@quininer`] for `no-std` support and rust implementation [`SP800-185`]
22//! - [`mimoo/GoKangarooTwelve`] for GO implementation of `KangarooTwelve`
23//! - [`@Vurich`] for optimizations
24//! - [`@oleganza`] for adding support for half-duplex use
25//!
26//! # License
27//!
28//! [`CC0`]. Attribution kindly requested. Blame taken too,
29//! but not liability.
30//!
31//! [`FIPS-202`]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
32//! [`SP800-185`]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf
33//! [`KangarooTwelve`]: https://eprint.iacr.org/2016/770.pdf
34//! [`coruus/keccak-tiny`]: https://github.com/coruus/keccak-tiny
35//! [`mimoo/GoKangarooTwelve`]: https://github.com/mimoo/GoKangarooTwelve
36//! [`@quininer`]: https://github.com/quininer
37//! [`@Vurich`]: https://github.com/Vurich
38//! [`@oleganza`]: https://github.com/oleganza
39//! [`CC0`]: https://github.com/debris/tiny-keccak/blob/master/LICENSE
40
41#![no_std]
42#![deny(missing_docs)]
43
44const RHO: [u32; 24] = [
45    1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
46];
47
48const PI: [usize; 24] = [
49    10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
50];
51
52const WORDS: usize = 25;
53
54macro_rules! keccak_function {
55    ($doc: expr, $name: ident, $rounds: expr, $rc: expr) => {
56        #[doc = $doc]
57        #[allow(unused_assignments)]
58        #[allow(non_upper_case_globals)]
59        pub fn $name(a: &mut [u64; $crate::WORDS]) {
60            use crunchy::unroll;
61
62            for i in 0..$rounds {
63                let mut array: [u64; 5] = [0; 5];
64
65                // Theta
66                unroll! {
67                    for x in 0..5 {
68                        unroll! {
69                            for y_count in 0..5 {
70                                let y = y_count * 5;
71                                array[x] ^= a[x + y];
72                            }
73                        }
74                    }
75                }
76
77                unroll! {
78                    for x in 0..5 {
79                        unroll! {
80                            for y_count in 0..5 {
81                                let y = y_count * 5;
82                                a[y + x] ^= array[(x + 4) % 5] ^ array[(x + 1) % 5].rotate_left(1);
83                            }
84                        }
85                    }
86                }
87
88                // Rho and pi
89                let mut last = a[1];
90                unroll! {
91                    for x in 0..24 {
92                        array[0] = a[$crate::PI[x]];
93                        a[$crate::PI[x]] = last.rotate_left($crate::RHO[x]);
94                        last = array[0];
95                    }
96                }
97
98                // Chi
99                unroll! {
100                    for y_step in 0..5 {
101                        let y = y_step * 5;
102
103                        unroll! {
104                            for x in 0..5 {
105                                array[x] = a[y + x];
106                            }
107                        }
108
109                        unroll! {
110                            for x in 0..5 {
111                                a[y + x] = array[x] ^ ((!array[(x + 1) % 5]) & (array[(x + 2) % 5]));
112                            }
113                        }
114                    }
115                };
116
117                // Iota
118                a[0] ^= $rc[i];
119            }
120        }
121    }
122}
123
124#[cfg(feature = "k12")]
125mod keccakp;
126
127#[cfg(feature = "k12")]
128pub use keccakp::keccakp;
129
130#[cfg(any(
131    feature = "keccak",
132    feature = "shake",
133    feature = "sha3",
134    feature = "cshake",
135    feature = "kmac",
136    feature = "tuple_hash",
137    feature = "parallel_hash"
138))]
139mod keccakf;
140
141#[cfg(any(
142    feature = "keccak",
143    feature = "shake",
144    feature = "sha3",
145    feature = "cshake",
146    feature = "kmac",
147    feature = "tuple_hash",
148    feature = "parallel_hash"
149))]
150pub use keccakf::keccakf;
151
152#[cfg(feature = "k12")]
153mod k12;
154
155#[cfg(feature = "k12")]
156pub use k12::{KangarooTwelve, KangarooTwelveXof};
157
158#[cfg(feature = "keccak")]
159mod keccak;
160
161#[cfg(feature = "keccak")]
162pub use keccak::Keccak;
163
164#[cfg(feature = "shake")]
165mod shake;
166
167#[cfg(feature = "shake")]
168pub use shake::Shake;
169
170#[cfg(feature = "sha3")]
171mod sha3;
172
173#[cfg(feature = "sha3")]
174pub use sha3::Sha3;
175
176#[cfg(feature = "cshake")]
177mod cshake;
178
179#[cfg(feature = "cshake")]
180pub use cshake::CShake;
181
182#[cfg(feature = "kmac")]
183mod kmac;
184
185#[cfg(feature = "kmac")]
186pub use kmac::{Kmac, KmacXof};
187
188#[cfg(feature = "tuple_hash")]
189mod tuple_hash;
190
191#[cfg(feature = "tuple_hash")]
192pub use tuple_hash::{TupleHash, TupleHashXof};
193
194#[cfg(feature = "parallel_hash")]
195mod parallel_hash;
196
197#[cfg(feature = "parallel_hash")]
198pub use parallel_hash::{ParallelHash, ParallelHashXof};
199
200/// A trait for hashing an arbitrary stream of bytes.
201///
202/// # Example
203///
204/// ```
205/// # use tiny_keccak::Hasher;
206/// #
207/// # fn foo<H: Hasher>(mut hasher: H) {
208/// let input_a = b"hello world";
209/// let input_b = b"!";
210/// let mut output = [0u8; 32];
211/// hasher.update(input_a);
212/// hasher.update(input_b);
213/// hasher.finalize(&mut output);
214/// # }
215/// ```
216pub trait Hasher {
217    /// Absorb additional input. Can be called multiple times.
218    fn update(&mut self, input: &[u8]);
219
220    /// Pad and squeeze the state to the output.
221    fn finalize(self, output: &mut [u8]);
222}
223
224/// A trait used to convert [`Hasher`] into it's [`Xof`] counterpart.
225///
226/// # Example
227///
228/// ```
229/// # use tiny_keccak::IntoXof;
230/// #
231/// # fn foo<H: IntoXof>(hasher: H) {
232/// let xof = hasher.into_xof();
233/// # }
234/// ```
235///
236/// [`Hasher`]: trait.Hasher.html
237/// [`Xof`]: trait.Xof.html
238pub trait IntoXof {
239    /// A type implementing [`Xof`], eXtendable-output function interface.
240    ///
241    /// [`Xof`]: trait.Xof.html
242    type Xof: Xof;
243
244    /// A method used to convert type into [`Xof`].
245    ///
246    /// [`Xof`]: trait.Xof.html
247    fn into_xof(self) -> Self::Xof;
248}
249
250/// Extendable-output function (`XOF`) is a function on bit strings in which the output can be
251/// extended to any desired length.
252///
253/// # Example
254///
255/// ```
256/// # use tiny_keccak::Xof;
257/// #
258/// # fn foo<X: Xof>(mut xof: X) {
259/// let mut output = [0u8; 64];
260/// xof.squeeze(&mut output[0..32]);
261/// xof.squeeze(&mut output[32..]);
262/// # }
263/// ```
264pub trait Xof {
265    /// A method used to retrieve another part of hash function output.
266    fn squeeze(&mut self, output: &mut [u8]);
267}
268
269struct EncodedLen {
270    offset: usize,
271    buffer: [u8; 9],
272}
273
274impl EncodedLen {
275    fn value(&self) -> &[u8] {
276        &self.buffer[self.offset..]
277    }
278}
279
280fn left_encode(len: usize) -> EncodedLen {
281    let mut buffer = [0u8; 9];
282    buffer[1..].copy_from_slice(&(len as u64).to_be_bytes());
283    let offset = buffer.iter().position(|i| *i != 0).unwrap_or(8);
284    buffer[offset - 1] = 9 - offset as u8;
285
286    EncodedLen {
287        offset: offset - 1,
288        buffer,
289    }
290}
291
292fn right_encode(len: usize) -> EncodedLen {
293    let mut buffer = [0u8; 9];
294    buffer[..8].copy_from_slice(&(len as u64).to_be_bytes());
295    let offset = buffer.iter().position(|i| *i != 0).unwrap_or(7);
296    buffer[8] = 8 - offset as u8;
297    EncodedLen { offset, buffer }
298}
299
300#[derive(Default, Clone)]
301struct Buffer([u64; WORDS]);
302
303impl Buffer {
304    fn words(&mut self) -> &mut [u64; WORDS] {
305        &mut self.0
306    }
307
308    #[cfg(target_endian = "little")]
309    #[inline]
310    fn execute<F: FnOnce(&mut [u8])>(&mut self, offset: usize, len: usize, f: F) {
311        let buffer: &mut [u8; WORDS * 8] = unsafe { core::mem::transmute(&mut self.0) };
312        f(&mut buffer[offset..][..len]);
313    }
314
315    #[cfg(target_endian = "big")]
316    #[inline]
317    fn execute<F: FnOnce(&mut [u8])>(&mut self, offset: usize, len: usize, f: F) {
318        fn swap_endianess(buffer: &mut [u64]) {
319            for item in buffer {
320                *item = item.swap_bytes();
321            }
322        }
323
324        let start = offset / 8;
325        let end = (offset + len + 7) / 8;
326        swap_endianess(&mut self.0[start..end]);
327        let buffer: &mut [u8; WORDS * 8] = unsafe { core::mem::transmute(&mut self.0) };
328        f(&mut buffer[offset..][..len]);
329        swap_endianess(&mut self.0[start..end]);
330    }
331
332    fn setout(&mut self, dst: &mut [u8], offset: usize, len: usize) {
333        self.execute(offset, len, |buffer| dst[..len].copy_from_slice(buffer));
334    }
335
336    fn xorin(&mut self, src: &[u8], offset: usize, len: usize) {
337        self.execute(offset, len, |dst| {
338            assert!(dst.len() <= src.len());
339            let len = dst.len();
340            let mut dst_ptr = dst.as_mut_ptr();
341            let mut src_ptr = src.as_ptr();
342            for _ in 0..len {
343                unsafe {
344                    *dst_ptr ^= *src_ptr;
345                    src_ptr = src_ptr.offset(1);
346                    dst_ptr = dst_ptr.offset(1);
347                }
348            }
349        });
350    }
351
352    fn pad(&mut self, offset: usize, delim: u8, rate: usize) {
353        self.execute(offset, 1, |buff| buff[0] ^= delim);
354        self.execute(rate - 1, 1, |buff| buff[0] ^= 0x80);
355    }
356}
357
358trait Permutation {
359    fn execute(a: &mut Buffer);
360}
361
362#[derive(Clone, Copy)]
363enum Mode {
364    Absorbing,
365    Squeezing,
366}
367
368struct KeccakState<P> {
369    buffer: Buffer,
370    offset: usize,
371    rate: usize,
372    delim: u8,
373    mode: Mode,
374    permutation: core::marker::PhantomData<P>,
375}
376
377impl<P> Clone for KeccakState<P> {
378    fn clone(&self) -> Self {
379        KeccakState {
380            buffer: self.buffer.clone(),
381            offset: self.offset,
382            rate: self.rate,
383            delim: self.delim,
384            mode: self.mode,
385            permutation: core::marker::PhantomData,
386        }
387    }
388}
389
390impl<P: Permutation> KeccakState<P> {
391    fn new(rate: usize, delim: u8) -> Self {
392        assert!(rate != 0, "rate cannot be equal 0");
393        KeccakState {
394            buffer: Buffer::default(),
395            offset: 0,
396            rate,
397            delim,
398            mode: Mode::Absorbing,
399            permutation: core::marker::PhantomData,
400        }
401    }
402
403    fn keccak(&mut self) {
404        P::execute(&mut self.buffer);
405    }
406
407    fn update(&mut self, input: &[u8]) {
408        if let Mode::Squeezing = self.mode {
409            self.mode = Mode::Absorbing;
410            self.fill_block();
411        }
412
413        //first foldp
414        let mut ip = 0;
415        let mut l = input.len();
416        let mut rate = self.rate - self.offset;
417        let mut offset = self.offset;
418        while l >= rate {
419            self.buffer.xorin(&input[ip..], offset, rate);
420            self.keccak();
421            ip += rate;
422            l -= rate;
423            rate = self.rate;
424            offset = 0;
425        }
426
427        self.buffer.xorin(&input[ip..], offset, l);
428        self.offset = offset + l;
429    }
430
431    fn pad(&mut self) {
432        self.buffer.pad(self.offset, self.delim, self.rate);
433    }
434
435    fn squeeze(&mut self, output: &mut [u8]) {
436        if let Mode::Absorbing = self.mode {
437            self.mode = Mode::Squeezing;
438            self.pad();
439            self.fill_block();
440        }
441
442        // second foldp
443        let mut op = 0;
444        let mut l = output.len();
445        let mut rate = self.rate - self.offset;
446        let mut offset = self.offset;
447        while l >= rate {
448            self.buffer.setout(&mut output[op..], offset, rate);
449            self.keccak();
450            op += rate;
451            l -= rate;
452            rate = self.rate;
453            offset = 0;
454        }
455
456        self.buffer.setout(&mut output[op..], offset, l);
457        self.offset = offset + l;
458    }
459
460    fn finalize(mut self, output: &mut [u8]) {
461        self.squeeze(output);
462    }
463
464    fn fill_block(&mut self) {
465        self.keccak();
466        self.offset = 0;
467    }
468
469    fn reset(&mut self) {
470        self.buffer = Buffer::default();
471        self.offset = 0;
472        self.mode = Mode::Absorbing;
473    }
474}
475
476fn bits_to_rate(bits: usize) -> usize {
477    200 - bits / 4
478}
479
480#[cfg(test)]
481mod tests {
482    use crate::{left_encode, right_encode};
483
484    #[test]
485    fn test_left_encode() {
486        assert_eq!(left_encode(0).value(), &[1, 0]);
487        assert_eq!(left_encode(128).value(), &[1, 128]);
488        assert_eq!(left_encode(65536).value(), &[3, 1, 0, 0]);
489        assert_eq!(left_encode(4096).value(), &[2, 16, 0]);
490        assert_eq!(left_encode(54321).value(), &[2, 212, 49]);
491    }
492
493    #[test]
494    fn test_right_encode() {
495        assert_eq!(right_encode(0).value(), &[0, 1]);
496        assert_eq!(right_encode(128).value(), &[128, 1]);
497        assert_eq!(right_encode(65536).value(), &[1, 0, 0, 3]);
498        assert_eq!(right_encode(4096).value(), &[16, 0, 2]);
499        assert_eq!(right_encode(54321).value(), &[212, 49, 2]);
500    }
501}