1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![cfg_attr(
4 any(
5 keccak_backend = "simd128",
6 keccak_backend = "simd256",
7 keccak_backend = "simd512",
8 ),
9 feature(portable_simd)
10)]
11#![doc = include_str!("../README.md")]
12#![doc(
13 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
14 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
15)]
16
17#[cfg(target_arch = "aarch64")]
18cpufeatures::new!(armv8_sha3_intrinsics, "sha3");
19
20pub mod backends;
21pub mod consts;
22pub mod types;
23
24pub use backends::*;
25pub use consts::*;
26pub use types::*;
27
28#[derive(Debug, Copy, Clone)]
30pub struct Keccak {
31 #[cfg(target_arch = "aarch64")]
32 armv8_sha3: armv8_sha3_intrinsics::InitToken,
33}
34
35impl Default for Keccak {
36 #[inline]
37 fn default() -> Self {
38 Self {
39 #[cfg(target_arch = "aarch64")]
40 armv8_sha3: armv8_sha3_intrinsics::init(),
41 }
42 }
43}
44
45impl Keccak {
46 #[inline]
48 #[must_use]
49 pub fn new() -> Self {
50 Self::default()
51 }
52
53 #[inline]
55 #[allow(unreachable_code)]
57 pub fn with_backend(&self, f: impl BackendClosure) {
58 cfg_if::cfg_if!(
59 if #[cfg(any(
60 keccak_backend = "simd128",
61 keccak_backend = "simd256",
62 keccak_backend = "simd512",
63 ))] {
64 return f.call_once::<simd::Backend>()
65 } else if #[cfg(keccak_backend = "aarch64_sha3")] {
66 #[cfg(not(target_arch = "aarch64"))]
67 compile_error!("aarch64_sha3 backend can be used only on AArch64 targets!");
68 #[cfg(not(target_feature = "sha3"))]
69 compile_error!("aarch64_sha3 backend requires sha3 target feature to be enabled!");
70
71 return f.call_once::<aarch64_sha3::Backend>()
72 } else if #[cfg(keccak_backend = "soft")] {
73 return f.call_once::<soft::Backend>()
74 }
75 );
76
77 #[cfg(target_arch = "aarch64")]
78 if self.armv8_sha3.get() {
79 #[target_feature(enable = "sha3")]
80 unsafe fn aarch64_sha3_inner(f: impl BackendClosure) {
81 f.call_once::<aarch64_sha3::Backend>();
82 }
83 return unsafe { aarch64_sha3_inner(f) };
85 }
86
87 f.call_once::<soft::Backend>();
88 }
89
90 #[inline]
92 pub fn with_f200(&self, f: impl FnOnce(Fn200)) {
93 self.with_p200::<F200_ROUNDS>(f);
94 }
95
96 #[inline]
98 pub fn with_f400(&self, f: impl FnOnce(Fn400)) {
99 self.with_p400::<F400_ROUNDS>(f);
100 }
101
102 #[inline]
104 pub fn with_f800(&self, f: impl FnOnce(Fn800)) {
105 self.with_p800::<F800_ROUNDS>(f);
106 }
107
108 #[inline]
110 pub fn with_f1600(&self, f: impl FnOnce(Fn1600)) {
111 self.with_p1600::<F1600_ROUNDS>(f);
112 }
113
114 #[inline]
119 pub fn with_p200<const ROUNDS: usize>(&self, f: impl FnOnce(Fn200)) {
120 f(soft::keccak_p::<u8, ROUNDS>);
121 }
122
123 #[inline]
128 pub fn with_p400<const ROUNDS: usize>(&self, f: impl FnOnce(Fn400)) {
129 f(soft::keccak_p::<u16, ROUNDS>);
130 }
131
132 #[inline]
137 pub fn with_p800<const ROUNDS: usize>(&self, f: impl FnOnce(Fn800)) {
138 f(soft::keccak_p::<u32, ROUNDS>);
139 }
140
141 #[inline]
146 pub fn with_p1600<const ROUNDS: usize>(&self, f: impl FnOnce(Fn1600)) {
147 struct Closure<const ROUNDS: usize, F: FnOnce(Fn1600)>(F);
148
149 impl<const ROUNDS: usize, F: FnOnce(Fn1600)> BackendClosure for Closure<ROUNDS, F> {
150 #[inline(always)]
151 fn call_once<B: Backend>(self) {
152 (self.0)(B::get_p1600::<ROUNDS>());
153 }
154 }
155
156 self.with_backend(Closure::<ROUNDS, _>(f));
157 }
158}