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    #[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    /// Create new Keccak backend.
47    #[inline]
48    #[must_use]
49    pub fn new() -> Self {
50        Self::default()
51    }
52
53    /// Execute the provided backend closure with Keccak backend.
54    #[inline]
55    // The auto-detection code will not be reached if `keccak_backend` is set.
56    #[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            // SAFETY: we checked target feature availability above
84            return unsafe { aarch64_sha3_inner(f) };
85        }
86
87        f.call_once::<soft::Backend>();
88    }
89
90    /// Execute the closure with `f200` function.
91    #[inline]
92    pub fn with_f200(&self, f: impl FnOnce(Fn200)) {
93        self.with_p200::<F200_ROUNDS>(f);
94    }
95
96    /// Execute the closure with `f400` function.
97    #[inline]
98    pub fn with_f400(&self, f: impl FnOnce(Fn400)) {
99        self.with_p400::<F400_ROUNDS>(f);
100    }
101
102    /// Execute the closure with `f800` function.
103    #[inline]
104    pub fn with_f800(&self, f: impl FnOnce(Fn800)) {
105        self.with_p800::<F800_ROUNDS>(f);
106    }
107
108    /// Execute the closure with `f1600` function.
109    #[inline]
110    pub fn with_f1600(&self, f: impl FnOnce(Fn1600)) {
111        self.with_p1600::<F1600_ROUNDS>(f);
112    }
113
114    /// Execute the closure with `p200` function with the specified number of rounds.
115    ///
116    /// # Panics
117    /// If `ROUNDS` is bigger than [`F200_ROUNDS`].
118    #[inline]
119    pub fn with_p200<const ROUNDS: usize>(&self, f: impl FnOnce(Fn200)) {
120        f(soft::keccak_p::<u8, ROUNDS>);
121    }
122
123    /// Execute the closure with `p200` function with the specified number of rounds.
124    ///
125    /// # Panics
126    /// If `ROUNDS` is bigger than [`F400_ROUNDS`].
127    #[inline]
128    pub fn with_p400<const ROUNDS: usize>(&self, f: impl FnOnce(Fn400)) {
129        f(soft::keccak_p::<u16, ROUNDS>);
130    }
131
132    /// Execute the closure with `p800` function with the specified number of rounds.
133    ///
134    /// # Panics
135    /// If `ROUNDS` is bigger than [`F800_ROUNDS`].
136    #[inline]
137    pub fn with_p800<const ROUNDS: usize>(&self, f: impl FnOnce(Fn800)) {
138        f(soft::keccak_p::<u32, ROUNDS>);
139    }
140
141    /// Execute the closure with `p1600` function with the specified number of rounds.
142    ///
143    /// # Panics
144    /// If `ROUNDS` is bigger than [`F1600_ROUNDS`].
145    #[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}