summaryrefslogtreecommitdiff
path: root/lib/crypto/s390/sha3.h
blob: 85471404775a33229c085d0236f19d6a11e598db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * SHA-3 optimized using the CP Assist for Cryptographic Functions (CPACF)
 *
 * Copyright 2025 Google LLC
 */
#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)) {
		/*
		 * Note that KIMD assumes little-endian order of the state
		 * words.  sha3_state already uses that order, though, so
		 * there's no need for a byteswap.
		 */
		switch (block_size) {
		case SHA3_224_BLOCK_SIZE:
			cpacf_kimd(CPACF_KIMD_SHA3_224, state,
				   data, nblocks * block_size);
			return;
		case SHA3_256_BLOCK_SIZE:
			/*
			 * This case handles both SHA3-256 and SHAKE256, since
			 * they have the same block size.
			 */
			cpacf_kimd(CPACF_KIMD_SHA3_256, state,
				   data, nblocks * block_size);
			return;
		case SHA3_384_BLOCK_SIZE:
			cpacf_kimd(CPACF_KIMD_SHA3_384, state,
				   data, nblocks * block_size);
			return;
		case SHA3_512_BLOCK_SIZE:
			cpacf_kimd(CPACF_KIMD_SHA3_512, state,
				   data, nblocks * block_size);
			return;
		}
	}
	sha3_absorb_blocks_generic(state, data, nblocks, block_size);
}

static void sha3_keccakf(struct sha3_state *state)
{
	if (static_branch_likely(&have_sha3)) {
		/*
		 * Passing zeroes into any of CPACF_KIMD_SHA3_* gives the plain
		 * Keccak-f permutation, which is what we want here.  Use
		 * SHA3-512 since it has the smallest block size.
		 */
		static const u8 zeroes[SHA3_512_BLOCK_SIZE];

		cpacf_kimd(CPACF_KIMD_SHA3_512, state, zeroes, sizeof(zeroes));
	} 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;

	if (!cpu_have_feature(S390_CPU_FEATURE_MSA))
		return;
	/*
	 * Since all the SHA-3 functions are in Message-Security-Assist
	 * Extension 6, just treat them as all or nothing.  This way we need
	 * only one static_key.
	 */
#define QUERY(opcode, func) \
	({ 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) {
		static_branch_enable(&have_sha3);
		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");
	}
}