dcrypt_algorithms/hash/keccak/
mod.rs1#[cfg(not(feature = "std"))]
10use alloc::vec::Vec;
11use zeroize::Zeroize;
12
13use crate::error::{validate, Result};
14use crate::hash::{Hash, HashAlgorithm, HashFunction};
15use crate::types::Digest;
16
17use core::sync::atomic::{compiler_fence, Ordering};
18
19use dcrypt_params::utils::hash::{KECCAK256_OUTPUT_SIZE, KECCAK256_BLOCK_SIZE};
20
21const KECCAK_ROUNDS: usize = 24;
22const KECCAK_STATE_SIZE: usize = 25; const KECCAK256_RATE: usize = KECCAK256_BLOCK_SIZE;
24
25const RC: [u64; KECCAK_ROUNDS] = [
27 0x0000_0000_0000_0001,
28 0x0000_0000_0000_8082,
29 0x8000_0000_0000_808A,
30 0x8000_0000_8000_8000,
31 0x0000_0000_0000_808B,
32 0x0000_0000_8000_0001,
33 0x8000_0000_8000_8081,
34 0x8000_0000_0000_8009,
35 0x0000_0000_0000_008A,
36 0x0000_0000_0000_0088,
37 0x0000_0000_8000_8009,
38 0x0000_0000_8000_000A,
39 0x0000_0000_8000_808B,
40 0x8000_0000_0000_008B,
41 0x8000_0000_0000_8089,
42 0x8000_0000_0000_8003,
43 0x8000_0000_0000_8002,
44 0x8000_0000_0000_0080,
45 0x0000_0000_0000_800A,
46 0x8000_0000_8000_000A,
47 0x8000_0000_8000_8081,
48 0x8000_0000_0000_8080,
49 0x0000_0000_8000_0001,
50 0x8000_0000_8000_8008,
51];
52
53const RHO: [u32; 24] = [
55 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
56];
57
58const PI: [usize; 24] = [
60 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
61];
62
63#[inline(always)]
66fn get_byte_from_state(state: &[u64; KECCAK_STATE_SIZE], pos: usize) -> u8 {
67 let word = pos / 8;
68 let shift = (pos % 8) * 8;
69 ((state[word] >> shift) & 0xFF) as u8
70}
71
72#[inline(always)]
73fn xor_byte_in_state(state: &mut [u64; KECCAK_STATE_SIZE], pos: usize, val: u8) {
74 let word = pos / 8;
75 let shift = (pos % 8) * 8;
76 let mask = (val as u64) << shift;
77
78 let before = state[word];
79 state[word] = before ^ mask;
80
81 compiler_fence(Ordering::SeqCst);
82}
83
84pub enum Keccak256Algorithm {}
88
89impl HashAlgorithm for Keccak256Algorithm {
90 const OUTPUT_SIZE: usize = KECCAK256_OUTPUT_SIZE;
91 const BLOCK_SIZE: usize = KECCAK256_RATE;
92 const ALGORITHM_ID: &'static str = "Keccak-256";
93}
94
95#[derive(Clone, Zeroize)]
99pub struct Keccak256 {
100 state: [u64; KECCAK_STATE_SIZE],
101 pt: usize,
102}
103
104impl Keccak256 {
105 #[inline(always)]
106 fn init() -> Self {
107 Self {
108 state: [0u64; KECCAK_STATE_SIZE],
109 pt: 0,
110 }
111 }
112 #[inline(always)]
113 fn rate() -> usize {
114 KECCAK256_RATE
115 }
116
117 fn update_internal(&mut self, data: &[u8]) -> Result<()> {
118 validate::parameter(
119 self.pt.checked_add(data.len()).is_some(),
120 "data_length",
121 "Integer overflow",
122 )?;
123 let r = Self::rate();
124 for &b in data {
125 xor_byte_in_state(&mut self.state, self.pt, b);
126 self.pt += 1;
127 if self.pt == r {
128 keccak_f1600(&mut self.state);
129 self.pt = 0;
130 }
131 }
132 Ok(())
133 }
134
135 fn finalize_internal(&mut self) -> Result<Hash> {
136 let r = Self::rate();
137 xor_byte_in_state(&mut self.state, self.pt, 0x01);
139 xor_byte_in_state(&mut self.state, r - 1, 0x80);
140 keccak_f1600(&mut self.state);
141
142 let mut out = vec![0u8; KECCAK256_OUTPUT_SIZE];
143 for i in 0..KECCAK256_OUTPUT_SIZE {
144 out[i] = get_byte_from_state(&self.state, i);
145 }
146
147 self.state = [0u64; KECCAK_STATE_SIZE];
148 self.pt = 0;
149 Ok(out)
150 }
151}
152
153impl HashFunction for Keccak256 {
154 type Algorithm = Keccak256Algorithm;
155 type Output = Digest<KECCAK256_OUTPUT_SIZE>;
156
157 fn new() -> Self {
158 Self::init()
159 }
160
161 fn update(&mut self, data: &[u8]) -> Result<&mut Self> {
162 self.update_internal(data)?;
163 Ok(self)
164 }
165
166 fn finalize(&mut self) -> Result<Self::Output> {
167 let h = self.finalize_internal()?;
168 let mut d = [0u8; KECCAK256_OUTPUT_SIZE];
169 d.copy_from_slice(&h);
170 Ok(Digest::new(d))
171 }
172
173 #[inline(always)]
174 fn output_size() -> usize {
175 <Keccak256Algorithm as HashAlgorithm>::OUTPUT_SIZE
176 }
177 #[inline(always)]
178 fn block_size() -> usize {
179 <Keccak256Algorithm as HashAlgorithm>::BLOCK_SIZE
180 }
181 #[inline(always)]
182 fn name() -> String {
183 <Keccak256Algorithm as HashAlgorithm>::ALGORITHM_ID.to_string()
184 }
185}
186
187fn keccak_f1600(state: &mut [u64; KECCAK_STATE_SIZE]) {
190 for &rc in RC.iter().take(KECCAK_ROUNDS) {
191 let mut c = [0u64; 5];
193 for x in 0..5 {
194 c[x] = state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^ state[x + 20];
195 }
196 for x in 0..5 {
197 let d = c[(x + 4) % 5] ^ c[(x + 1) % 5].rotate_left(1);
198 for y in 0..5 {
199 state[x + 5 * y] ^= d;
200 }
201 }
202 let mut t = state[1];
204 for i in 0..24 {
205 let j = PI[i];
206 let tmp = state[j];
207 state[j] = t.rotate_left(RHO[i]);
208 t = tmp;
209 }
210 for y in 0..5 {
212 let mut row = [0u64; 5];
213 for x in 0..5 {
214 row[x] = state[x + 5 * y];
215 }
216 for x in 0..5 {
217 state[x + 5 * y] ^= (!row[(x + 1) % 5]) & row[(x + 2) % 5];
218 }
219 }
220 state[0] ^= rc;
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn test_keccak256_empty() {
231 let digest = Keccak256::digest(b"").unwrap();
233 let expected = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
235 assert_eq!(digest.to_hex(), expected);
236 }
237
238 #[test]
239 fn test_keccak256_string() {
240 let digest = Keccak256::digest(b"Hello, world!").unwrap();
242 let expected = "b6e16d27ac5ab427a7f68900ac5559ce272dc6c37c82b3e052246c82244c50e4";
244 assert_eq!(digest.to_hex(), expected);
245 }
246}