Skip to main content

ethrex_crypto/keccak/
mod.rs

1#[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                // partial block
58                if self.tail_len > 0 {
59                    let need = BLOCK_SIZE - self.tail_len;
60                    if data.len() < need {
61                        // still partial block
62                        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                    // complete block
69                    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}