ethrex_crypto/keccak/
mod.rs1#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
2core::arch::global_asm!(include_str!("keccak1600-armv8-elf.s"), options(raw));
3#[cfg(all(target_arch = "aarch64", target_os = "macos"))]
4core::arch::global_asm!(include_str!("keccak1600-armv8-macho.s"), options(raw));
5#[cfg(target_arch = "x86_64")]
6core::arch::global_asm!(include_str!("keccak1600-x86_64.s"), options(att_syntax));
7
8pub use imp::*;
9
10#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
11mod imp {
12 const BLOCK_SIZE: usize = 136;
13
14 #[derive(Default, Clone, Copy)]
15 #[repr(transparent)]
16 struct State([u64; 25]);
17
18 unsafe extern "C" {
19 #[link_name = "SHA3_absorb"]
20 unsafe fn SHA3_absorb(state: *mut State, buf: *const u8, len: usize, r: usize) -> usize;
21 unsafe fn SHA3_squeeze(state: *mut State, buf: *mut u8, len: usize, r: usize);
22 }
23
24 pub fn keccak_hash(data: impl AsRef<[u8]>) -> [u8; 32] {
25 let mut state = Keccak256::new();
26 state.update(data);
27 state.finalize()
28 }
29
30 #[derive(Clone)]
31 pub struct Keccak256 {
32 state: State,
33 tail_buf: [u8; BLOCK_SIZE],
34 tail_len: usize,
35 }
36
37 impl Default for Keccak256 {
38 fn default() -> Self {
39 Self {
40 state: State::default(),
41 tail_buf: [0; BLOCK_SIZE],
42 tail_len: 0,
43 }
44 }
45 }
46
47 impl Keccak256 {
48 #[inline]
49 pub fn new() -> Self {
50 Self::default()
51 }
52
53 #[inline]
54 pub fn update(&mut self, data: impl AsRef<[u8]>) -> Self {
55 let mut data = data.as_ref();
56 unsafe {
57 if self.tail_len > 0 {
59 let need = BLOCK_SIZE - self.tail_len;
60 if data.len() < need {
61 self.tail_buf[self.tail_len..self.tail_len + data.len()]
63 .copy_from_slice(data);
64 self.tail_len += data.len();
65 return self.clone();
66 }
67
68 self.tail_buf[self.tail_len..BLOCK_SIZE].copy_from_slice(&data[..need]);
70
71 SHA3_absorb(
72 &mut self.state,
73 self.tail_buf.as_ptr(),
74 self.tail_buf.len(),
75 BLOCK_SIZE,
76 );
77
78 self.tail_len = 0;
79 self.tail_buf.fill(0);
80 data = &data[need..];
81 }
82 }
83
84 match data {
85 [] => {}
86 data if data.len() < BLOCK_SIZE => unsafe {
87 self.tail_len = data.len();
88 self.tail_buf
89 .get_unchecked_mut(..self.tail_len)
90 .copy_from_slice(data);
91 },
92 data => unsafe {
93 let rem = SHA3_absorb(&mut self.state, data.as_ptr(), data.len(), BLOCK_SIZE);
94 self.tail_len = rem;
95 if rem != 0 {
96 let tail_data = data.get_unchecked(data.len() - rem..);
97 self.tail_buf
98 .get_unchecked_mut(..rem)
99 .copy_from_slice(tail_data);
100 }
101 },
102 }
103 self.clone()
104 }
105
106 #[inline]
107 pub fn finalize(mut self) -> [u8; 32] {
108 let mut hash_buf = [0u8; 32];
109
110 unsafe {
111 *self.tail_buf.get_unchecked_mut(self.tail_len) = 0x01;
112 *self.tail_buf.get_unchecked_mut(BLOCK_SIZE - 1) |= 0x80;
113
114 SHA3_absorb(
115 &mut self.state,
116 self.tail_buf.as_ptr(),
117 self.tail_buf.len(),
118 BLOCK_SIZE,
119 );
120
121 SHA3_squeeze(
122 &mut self.state,
123 hash_buf.as_mut_ptr(),
124 hash_buf.len(),
125 BLOCK_SIZE,
126 );
127 }
128
129 hash_buf
130 }
131 }
132}
133
134#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
135mod imp {
136 use tiny_keccak::{Hasher, Keccak};
137
138 pub fn keccak_hash(data: impl AsRef<[u8]>) -> [u8; 32] {
139 let mut out = [0u8; 32];
140 let mut h = Keccak::v256();
141 h.update(data.as_ref());
142 h.finalize(&mut out);
143 out
144 }
145
146 #[derive(Clone)]
147 pub struct Keccak256 {
148 h: Keccak,
149 }
150
151 impl Default for Keccak256 {
152 fn default() -> Self {
153 Self::new()
154 }
155 }
156
157 impl Keccak256 {
158 #[inline]
159 pub fn new() -> Self {
160 Self { h: Keccak::v256() }
161 }
162
163 #[inline]
164 pub fn update(&mut self, data: impl AsRef<[u8]>) -> Self {
165 let d = data.as_ref();
166 if !d.is_empty() {
167 self.h.update(d);
168 }
169 self.clone()
170 }
171
172 #[inline]
173 pub fn finalize(self) -> [u8; 32] {
174 let mut out = [0u8; 32];
175 self.h.finalize(&mut out);
176 out
177 }
178 }
179}