groestl/
lib.rs

1//! An implementation of the [Grøstl][1] cryptographic hash function.
2//!
3//! # Usage
4//!
5//! ```
6//! use groestl::{Digest, Groestl256};
7//! use hex_literal::hex;
8//!
9//! // create a Groestl-256 hasher instance
10//! let mut hasher = Groestl256::default();
11//!
12//! // process input message
13//! hasher.update(b"my message");
14//!
15//! // acquire hash digest in the form of GenericArray,
16//! // which in this case is equivalent to [u8; 32]
17//! let result = hasher.finalize();
18//! assert_eq!(result[..], hex!("
19//!     dc0283ca481efa76b7c19dd5a0b763dff0e867451bd9488a9c59f6c8b8047a86
20//! "));
21//! ```
22//!
23//! Also see [RustCrypto/hashes][2] readme.
24//!
25//! [1]: https://en.wikipedia.org/wiki/Grøstl
26//! [2]: https://github.com/RustCrypto/hashes
27
28#![no_std]
29#![doc(
30    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
31    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
32    html_root_url = "https://docs.rs/groestl/0.10.1"
33)]
34#![forbid(unsafe_code)]
35#![warn(rust_2018_idioms)]
36
37pub use digest::{self, Digest};
38
39use core::fmt;
40use digest::{
41    block_buffer::Eager,
42    core_api::{
43        AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper,
44        CtVariableCoreWrapper, OutputSizeUser, RtVariableCoreWrapper, TruncSide, UpdateCore,
45        VariableOutputCore,
46    },
47    typenum::{Unsigned, U128, U28, U32, U48, U64},
48    HashMarker, InvalidOutputSize, Output,
49};
50
51mod compress1024;
52mod compress512;
53mod table;
54
55/// Lowest-level core hasher state of the short Groestl variant.
56#[derive(Clone)]
57pub struct GroestlShortVarCore {
58    state: [u64; compress512::COLS],
59    blocks_len: u64,
60}
61
62impl HashMarker for GroestlShortVarCore {}
63
64impl BlockSizeUser for GroestlShortVarCore {
65    type BlockSize = U64;
66}
67
68impl BufferKindUser for GroestlShortVarCore {
69    type BufferKind = Eager;
70}
71
72impl UpdateCore for GroestlShortVarCore {
73    #[inline]
74    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
75        self.blocks_len += blocks.len() as u64;
76        for block in blocks {
77            compress512::compress(&mut self.state, block.as_ref());
78        }
79    }
80}
81
82impl OutputSizeUser for GroestlShortVarCore {
83    type OutputSize = U32;
84}
85
86impl VariableOutputCore for GroestlShortVarCore {
87    const TRUNC_SIDE: TruncSide = TruncSide::Right;
88
89    #[inline]
90    fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
91        if output_size > Self::OutputSize::USIZE {
92            return Err(InvalidOutputSize);
93        }
94        let mut state = [0; compress512::COLS];
95        state[compress512::COLS - 1] = 8 * output_size as u64;
96        let blocks_len = 0;
97        Ok(Self { state, blocks_len })
98    }
99
100    #[inline]
101    fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
102        let blocks_len = if buffer.remaining() <= 8 {
103            self.blocks_len + 2
104        } else {
105            self.blocks_len + 1
106        };
107        buffer.len64_padding_be(blocks_len, |block| {
108            compress512::compress(&mut self.state, block.as_ref())
109        });
110        let res = compress512::p(&self.state);
111        let n = compress512::COLS / 2;
112        for (chunk, v) in out.chunks_exact_mut(8).zip(res[n..].iter()) {
113            chunk.copy_from_slice(&v.to_be_bytes());
114        }
115    }
116}
117
118impl AlgorithmName for GroestlShortVarCore {
119    #[inline]
120    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
121        f.write_str("GroestlShort")
122    }
123}
124
125impl fmt::Debug for GroestlShortVarCore {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        f.write_str("GroestlShortVarCore { ... }")
128    }
129}
130
131/// Short Groestl variant which allows to choose output size at runtime.
132pub type GroestlShortVar = RtVariableCoreWrapper<GroestlShortVarCore>;
133/// Core hasher state of the short Groestl variant generic over output size.
134pub type GroestlShortCore<OutSize> = CtVariableCoreWrapper<GroestlShortVarCore, OutSize>;
135/// Hasher state of the short Groestl variant generic over output size.
136pub type GroestlShort<OutSize> = CoreWrapper<GroestlShortCore<OutSize>>;
137
138/// Groestl-224 hasher state.
139pub type Groestl224 = CoreWrapper<GroestlShortCore<U28>>;
140/// Groestl-256 hasher state.
141pub type Groestl256 = CoreWrapper<GroestlShortCore<U32>>;
142
143/// Lowest-level core hasher state of the long Groestl variant.
144#[derive(Clone)]
145pub struct GroestlLongVarCore {
146    state: [u64; compress1024::COLS],
147    blocks_len: u64,
148}
149
150impl HashMarker for GroestlLongVarCore {}
151
152impl BlockSizeUser for GroestlLongVarCore {
153    type BlockSize = U128;
154}
155
156impl BufferKindUser for GroestlLongVarCore {
157    type BufferKind = Eager;
158}
159
160impl UpdateCore for GroestlLongVarCore {
161    #[inline]
162    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
163        self.blocks_len += blocks.len() as u64;
164        for block in blocks {
165            compress1024::compress(&mut self.state, block.as_ref());
166        }
167    }
168}
169
170impl OutputSizeUser for GroestlLongVarCore {
171    type OutputSize = U64;
172}
173
174impl VariableOutputCore for GroestlLongVarCore {
175    const TRUNC_SIDE: TruncSide = TruncSide::Right;
176
177    #[inline]
178    fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
179        if output_size > Self::OutputSize::USIZE {
180            return Err(InvalidOutputSize);
181        }
182        let mut state = [0; compress1024::COLS];
183        state[compress1024::COLS - 1] = 8 * output_size as u64;
184        let blocks_len = 0;
185        Ok(Self { state, blocks_len })
186    }
187
188    #[inline]
189    fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
190        let blocks_len = if buffer.remaining() <= 8 {
191            self.blocks_len + 2
192        } else {
193            self.blocks_len + 1
194        };
195        buffer.len64_padding_be(blocks_len, |block| {
196            compress1024::compress(&mut self.state, block.as_ref())
197        });
198        let res = compress1024::p(&self.state);
199        let n = compress1024::COLS / 2;
200        for (chunk, v) in out.chunks_exact_mut(8).zip(res[n..].iter()) {
201            chunk.copy_from_slice(&v.to_be_bytes());
202        }
203    }
204}
205
206impl AlgorithmName for GroestlLongVarCore {
207    #[inline]
208    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        f.write_str("GroestlLong")
210    }
211}
212
213impl fmt::Debug for GroestlLongVarCore {
214    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215        f.write_str("GroestlLongVarCore { ... }")
216    }
217}
218
219/// Long Groestl variant which allows to choose output size at runtime.
220pub type GroestlLongVar = RtVariableCoreWrapper<GroestlLongVarCore>;
221/// Core hasher state of the long Groestl variant generic over output size.
222pub type GroestlLongCore<OutSize> = CtVariableCoreWrapper<GroestlLongVarCore, OutSize>;
223/// Hasher state of the long Groestl variant generic over output size.
224pub type GroestlLong<OutSize> = CoreWrapper<GroestlLongCore<OutSize>>;
225
226/// Groestl-384 hasher state.
227pub type Groestl384 = CoreWrapper<GroestlLongCore<U48>>;
228/// Groestl-512 hasher state.
229pub type Groestl512 = CoreWrapper<GroestlLongCore<U64>>;