keccak_rust/
lib.rs

1#![crate_type = "lib"]
2#![crate_name = "keccak_rust"]
3
4mod keccak_f;
5use keccak_f::*;
6
7mod sponge;
8use sponge::*;
9
10pub type BitsWidth = usize;
11
12pub type Rate = usize;
13pub type Capacity = usize;
14pub type Security = (Rate, Capacity);
15
16pub type Byte = u8;
17pub type State = [[u64; 5]; 5];
18pub type BytesVec = Vec<Byte>;
19pub type BytesArr = [Byte];
20
21pub type PermutationsNum = usize;
22
23// SHA224, SHA256, SHA384, SHA512
24static RATES: [usize; 4] = [1152, 1088, 832, 576];
25static CAPACITIES: [usize; 4] = [448, 512, 768, 1024];
26
27// F25, F50, F100, F200, F400, F800, F1600
28static PERMUTATIONS_NUM: [usize; 7] = [12, 14, 16, 18, 20, 22, 24];
29
30static ROUND_CONSTANTS: [u64; 24] = [
31    0x0000000000000001,
32    0x0000000000008082,
33    0x800000000000808A,
34    0x8000000080008000,
35    0x000000000000808B,
36    0x0000000080000001,
37    0x8000000080008081,
38    0x8000000000008009,
39    0x000000000000008A,
40    0x0000000000000088,
41    0x0000000080008009,
42    0x000000008000000A,
43    0x000000008000808B,
44    0x800000000000008B,
45    0x8000000000008089,
46    0x8000000000008003,
47    0x8000000000008002,
48    0x8000000000000080,
49    0x000000000000800A,
50    0x800000008000000A,
51    0x8000000080008081,
52    0x8000000000008080,
53    0x0000000080000001,
54    0x8000000080008008,
55];
56
57static ROTATION_CONSTANTS: State = [
58    [0, 36, 3, 41, 18],
59    [1, 44, 10, 45, 2],
60    [62, 6, 43, 15, 61],
61    [28, 55, 25, 21, 56],
62    [27, 20, 39, 8, 14],
63];
64
65pub enum StateBitsWidth {
66    F25,
67    F50,
68    F100,
69    F200,
70    F400,
71    F800,
72    F1600,
73    Custom(BitsWidth),
74}
75
76pub enum SecurityLevel {
77    SHA224,
78    SHA256,
79    SHA384,
80    SHA512,
81    Custom(Security),
82}
83
84/// An implementation of keccak functions. [`The Keccak reference`].
85///
86/// # Example
87///
88/// ```toml
89/// [dependencies]
90/// keccak-rust = *
91/// ```
92///
93/// ```rust
94/// extern crate keccak_rust;
95/// use keccak_rust::*;
96///
97/// const YOUR_INPUT_BYTES: [u8; 12] = [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33];
98///
99/// fn main() {
100///     let mut keccak = Keccak::new(SecurityLevel::SHA256, StateBitsWidth::F1600);
101///     keccak.append(&mut YOUR_INPUT_BYTES);
102///     println!("{:?}", keccak.hash());
103/// }
104/// ```
105///
106/// [`The Keccak reference`]: https://keccak.team/files/Keccak-reference-3.0.pdf
107pub struct Keccak {
108    state: State,
109    sponge: Sponge,
110}
111
112impl Keccak {
113    /// Creates a new keccak state with a provided security level and state bits width.
114    ///
115    /// Possible securities levels:
116    /// - SHA224 (224 bit)
117    /// - SHA256 (256 bit)
118    /// - SHA384 (384 bit)
119    /// - SHA512 (512 bit)
120    ///
121    /// Possible state bits widths:
122    /// - f25
123    /// - f50
124    /// - f100
125    /// - f200
126    /// - f400
127    /// - f800
128    /// - f1600
129    pub fn new(security: SecurityLevel, width: StateBitsWidth) -> Keccak {
130        let security_level = match security {
131            SecurityLevel::SHA224 => (RATES[0], CAPACITIES[0]),
132            SecurityLevel::SHA256 => (RATES[1], CAPACITIES[1]),
133            SecurityLevel::SHA384 => (RATES[2], CAPACITIES[2]),
134            SecurityLevel::SHA512 => (RATES[3], CAPACITIES[3]),
135            SecurityLevel::Custom(security) => (security.0, security.1),
136        };
137
138        Keccak {
139            state: [[0; 5]; 5],
140            // rate & capacity in bytes
141            sponge: Sponge::new(security_level.0 / 8, security_level.1 / 8, width),
142        }
143    }
144
145    /// Appends input to current state
146    pub fn append(&mut self, input: &BytesArr) {
147        let padding_total = self.sponge.rate - (input.len() % self.sponge.rate);
148        let mut padding: Vec<Byte>;
149
150        if padding_total == 1 {
151            padding = vec![0x81];
152        } else {
153            padding = vec![];
154            padding.push(0x01);
155
156            for _ in 0..(padding_total - 2) {
157                padding.push(0x00);
158            }
159
160            padding.push(0x80);
161        }
162
163        let padded_input: &BytesArr = &[input, &padding].concat();
164        self.sponge.absorb(&mut self.state, padded_input);
165    }
166
167    /// Returns keccak hash based on current state
168    pub fn hash(&mut self) -> BytesVec {
169        self.sponge.squeeze(&mut self.state)
170    }
171}