Skip to main content

keccak/
lib.rs

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/// Struct which handles switching between available backends.
29#[derive(Debug, Copy, Clone)]
30pub struct Keccak {
31    // TODO: remove `not(target_abi = "softfloat")` after the compiler is improved, see:
32    // https://github.com/rust-lang/rust/issues/160301
33    #[cfg(all(target_arch = "aarch64", not(target_abi = "softfloat")))]
34    armv8_sha3: armv8_sha3_intrinsics::InitToken,
35}
36
37impl Default for Keccak {
38    #[inline]
39    fn default() -> Self {
40        Self {
41            #[cfg(all(target_arch = "aarch64", not(target_abi = "softfloat")))]
42            armv8_sha3: armv8_sha3_intrinsics::init(),
43        }
44    }
45}
46
47impl Keccak {
48    /// Create new Keccak backend.
49    #[inline]
50    #[must_use]
51    pub fn new() -> Self {
52        Self::default()
53    }
54
55    /// Execute the provided backend closure with Keccak backend.
56    #[inline]
57    // The auto-detection code will not be reached if `keccak_backend` is set.
58    #[allow(unreachable_code)]
59    pub fn with_backend(&self, f: impl BackendClosure) {
60        cfg_if::cfg_if!(
61            if #[cfg(any(
62                keccak_backend = "simd128",
63                keccak_backend = "simd256",
64                keccak_backend = "simd512",
65            ))] {
66                return f.call_once::<simd::Backend>()
67            } else if #[cfg(keccak_backend = "aarch64_sha3")] {
68                #[cfg(not(target_arch = "aarch64"))]
69                compile_error!("aarch64_sha3 backend can be used only on AArch64 targets!");
70                #[cfg(target_abi = "softfloat")]
71                compile_error!("aarch64_sha3 backend can not be used with softfloat ABI!");
72                #[cfg(not(target_feature = "sha3"))]
73                compile_error!("aarch64_sha3 backend requires sha3 target feature to be enabled!");
74
75                return f.call_once::<aarch64_sha3::Backend>()
76            } else if #[cfg(keccak_backend = "soft")] {
77                return f.call_once::<soft::Backend>()
78            }
79        );
80
81        #[cfg(all(target_arch = "aarch64", not(target_abi = "softfloat")))]
82        if self.armv8_sha3.get() {
83            #[target_feature(enable = "sha3")]
84            unsafe fn aarch64_sha3_inner(f: impl BackendClosure) {
85                f.call_once::<aarch64_sha3::Backend>();
86            }
87            // SAFETY: we checked target feature availability above
88            return unsafe { aarch64_sha3_inner(f) };
89        }
90
91        f.call_once::<soft::Backend>();
92    }
93
94    /// Execute the closure with `f200` function.
95    #[inline]
96    pub fn with_f200(&self, f: impl FnOnce(Fn200)) {
97        self.with_p200::<F200_ROUNDS>(f);
98    }
99
100    /// Execute the closure with `f400` function.
101    #[inline]
102    pub fn with_f400(&self, f: impl FnOnce(Fn400)) {
103        self.with_p400::<F400_ROUNDS>(f);
104    }
105
106    /// Execute the closure with `f800` function.
107    #[inline]
108    pub fn with_f800(&self, f: impl FnOnce(Fn800)) {
109        self.with_p800::<F800_ROUNDS>(f);
110    }
111
112    /// Execute the closure with `f1600` function.
113    #[inline]
114    pub fn with_f1600(&self, f: impl FnOnce(Fn1600)) {
115        self.with_p1600::<F1600_ROUNDS>(f);
116    }
117
118    /// Execute the closure with `p200` function with the specified number of rounds.
119    ///
120    /// # Panics
121    /// If `ROUNDS` is bigger than [`F200_ROUNDS`].
122    #[inline]
123    pub fn with_p200<const ROUNDS: usize>(&self, f: impl FnOnce(Fn200)) {
124        f(soft::keccak_p::<u8, ROUNDS>);
125    }
126
127    /// Execute the closure with `p200` function with the specified number of rounds.
128    ///
129    /// # Panics
130    /// If `ROUNDS` is bigger than [`F400_ROUNDS`].
131    #[inline]
132    pub fn with_p400<const ROUNDS: usize>(&self, f: impl FnOnce(Fn400)) {
133        f(soft::keccak_p::<u16, ROUNDS>);
134    }
135
136    /// Execute the closure with `p800` function with the specified number of rounds.
137    ///
138    /// # Panics
139    /// If `ROUNDS` is bigger than [`F800_ROUNDS`].
140    #[inline]
141    pub fn with_p800<const ROUNDS: usize>(&self, f: impl FnOnce(Fn800)) {
142        f(soft::keccak_p::<u32, ROUNDS>);
143    }
144
145    /// Execute the closure with `p1600` function with the specified number of rounds.
146    ///
147    /// # Panics
148    /// If `ROUNDS` is bigger than [`F1600_ROUNDS`].
149    #[inline]
150    pub fn with_p1600<const ROUNDS: usize>(&self, f: impl FnOnce(Fn1600)) {
151        struct Closure<const ROUNDS: usize, F: FnOnce(Fn1600)>(F);
152
153        impl<const ROUNDS: usize, F: FnOnce(Fn1600)> BackendClosure for Closure<ROUNDS, F> {
154            #[inline(always)]
155            fn call_once<B: Backend>(self) {
156                (self.0)(B::get_p1600::<ROUNDS>());
157            }
158        }
159
160        self.with_backend(Closure::<ROUNDS, _>(f));
161    }
162}