[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251026055032.1413733-13-ebiggers@kernel.org>
Date: Sat, 25 Oct 2025 22:50:29 -0700
From: Eric Biggers <ebiggers@...nel.org>
To: linux-crypto@...r.kernel.org
Cc: David Howells <dhowells@...hat.com>,
Ard Biesheuvel <ardb@...nel.org>,
"Jason A . Donenfeld" <Jason@...c4.com>,
Eric Biggers <ebiggers@...nel.org>,
Holger Dengler <dengler@...ux.ibm.com>,
Harald Freudenberger <freude@...ux.ibm.com>,
Herbert Xu <herbert@...dor.apana.org.au>,
linux-arm-kernel@...ts.infradead.org,
linux-s390@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH v2 12/15] lib/crypto: s390/sha3: Add optimized one-shot SHA-3 digest functions
Some z/Architecture processors can compute a SHA-3 digest in a single
instruction. Use this capability to implement the sha3_224(),
sha3_256(), sha3_384(), and sha3_512() library functions.
Note that the performance improvement is likely to be relatively small
and be noticeable primarily on short messages, as the actual Keccak
permutation is already accelerated via the implementations of
sha3_absorb_blocks() and sha3_keccakf(). Nevertheless,
arch/s390/crypto/ takes advantage of the "do the full SHA-3" capability,
and it was requested that lib/crypto/ do so as well for parity with it.
Signed-off-by: Eric Biggers <ebiggers@...nel.org>
---
lib/crypto/s390/sha3.h | 67 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 65 insertions(+), 2 deletions(-)
diff --git a/lib/crypto/s390/sha3.h b/lib/crypto/s390/sha3.h
index 668e53da93d2c..85471404775a3 100644
--- a/lib/crypto/s390/sha3.h
+++ b/lib/crypto/s390/sha3.h
@@ -6,10 +6,11 @@
*/
#include <asm/cpacf.h>
#include <linux/cpufeature.h>
static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_sha3);
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_sha3_init_optim);
static void sha3_absorb_blocks(struct sha3_state *state, const u8 *data,
size_t nblocks, size_t block_size)
{
if (static_branch_likely(&have_sha3)) {
@@ -58,10 +59,65 @@ static void sha3_keccakf(struct sha3_state *state)
} else {
sha3_keccakf_generic(state);
}
}
+static inline bool s390_sha3(int func, const u8 *in, size_t in_len,
+ u8 *out, size_t out_len)
+{
+ struct sha3_state state;
+
+ if (!static_branch_likely(&have_sha3))
+ return false;
+
+ if (static_branch_likely(&have_sha3_init_optim))
+ func |= CPACF_KLMD_NIP | CPACF_KLMD_DUFOP;
+ else
+ memset(&state, 0, sizeof(state));
+
+ cpacf_klmd(func, &state, in, in_len);
+
+ if (static_branch_likely(&have_sha3_init_optim))
+ kmsan_unpoison_memory(&state, out_len);
+
+ memcpy(out, &state, out_len);
+ memzero_explicit(&state, sizeof(state));
+ return true;
+}
+
+#define sha3_224_arch sha3_224_arch
+static bool sha3_224_arch(const u8 *in, size_t in_len,
+ u8 out[SHA3_224_DIGEST_SIZE])
+{
+ return s390_sha3(CPACF_KLMD_SHA3_224, in, in_len,
+ out, SHA3_224_DIGEST_SIZE);
+}
+
+#define sha3_256_arch sha3_256_arch
+static bool sha3_256_arch(const u8 *in, size_t in_len,
+ u8 out[SHA3_256_DIGEST_SIZE])
+{
+ return s390_sha3(CPACF_KLMD_SHA3_256, in, in_len,
+ out, SHA3_256_DIGEST_SIZE);
+}
+
+#define sha3_384_arch sha3_384_arch
+static bool sha3_384_arch(const u8 *in, size_t in_len,
+ u8 out[SHA3_384_DIGEST_SIZE])
+{
+ return s390_sha3(CPACF_KLMD_SHA3_384, in, in_len,
+ out, SHA3_384_DIGEST_SIZE);
+}
+
+#define sha3_512_arch sha3_512_arch
+static bool sha3_512_arch(const u8 *in, size_t in_len,
+ u8 out[SHA3_512_DIGEST_SIZE])
+{
+ return s390_sha3(CPACF_KLMD_SHA3_512, in, in_len,
+ out, SHA3_512_DIGEST_SIZE);
+}
+
#define sha3_mod_init_arch sha3_mod_init_arch
static void sha3_mod_init_arch(void)
{
int num_present = 0;
int num_possible = 0;
@@ -77,12 +133,19 @@ static void sha3_mod_init_arch(void)
({ num_present += !!cpacf_query_func(opcode, func); num_possible++; })
QUERY(CPACF_KIMD, CPACF_KIMD_SHA3_224);
QUERY(CPACF_KIMD, CPACF_KIMD_SHA3_256);
QUERY(CPACF_KIMD, CPACF_KIMD_SHA3_384);
QUERY(CPACF_KIMD, CPACF_KIMD_SHA3_512);
+ QUERY(CPACF_KLMD, CPACF_KLMD_SHA3_224);
+ QUERY(CPACF_KLMD, CPACF_KLMD_SHA3_256);
+ QUERY(CPACF_KLMD, CPACF_KLMD_SHA3_384);
+ QUERY(CPACF_KLMD, CPACF_KLMD_SHA3_512);
#undef QUERY
- if (num_present == num_possible)
+ if (num_present == num_possible) {
static_branch_enable(&have_sha3);
- else if (num_present != 0)
+ if (test_facility(86))
+ static_branch_enable(&have_sha3_init_optim);
+ } else if (num_present != 0) {
pr_warn("Unsupported combination of SHA-3 facilities\n");
+ }
}
--
2.51.1.dirty
Powered by blists - more mailing lists