xref: /linux/lib/crypto/arm64/gf128hash.h (revision 370c3883195566ee3e7d79e0146c3d735a406573)
161f66c52SEric Biggers /* SPDX-License-Identifier: GPL-2.0-or-later */
261f66c52SEric Biggers /*
3a336c01fSEric Biggers  * GHASH and POLYVAL, arm64 optimized
461f66c52SEric Biggers  *
561f66c52SEric Biggers  * Copyright 2025 Google LLC
661f66c52SEric Biggers  */
761f66c52SEric Biggers #include <asm/simd.h>
861f66c52SEric Biggers #include <linux/cpufeature.h>
961f66c52SEric Biggers 
1061f66c52SEric Biggers #define NUM_H_POWERS 8
1161f66c52SEric Biggers 
12a336c01fSEric Biggers static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_asimd);
1361f66c52SEric Biggers static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_pmull);
1461f66c52SEric Biggers 
15a336c01fSEric Biggers asmlinkage void pmull_ghash_update_p8(size_t blocks, struct polyval_elem *dg,
16a336c01fSEric Biggers 				      const u8 *src,
17a336c01fSEric Biggers 				      const struct polyval_elem *h);
1861f66c52SEric Biggers asmlinkage void polyval_mul_pmull(struct polyval_elem *a,
1961f66c52SEric Biggers 				  const struct polyval_elem *b);
2061f66c52SEric Biggers asmlinkage void polyval_blocks_pmull(struct polyval_elem *acc,
2161f66c52SEric Biggers 				     const struct polyval_key *key,
2261f66c52SEric Biggers 				     const u8 *data, size_t nblocks);
2361f66c52SEric Biggers 
24b3b6e8f9SEric Biggers #define polyval_preparekey_arch polyval_preparekey_arch
2561f66c52SEric Biggers static void polyval_preparekey_arch(struct polyval_key *key,
2661f66c52SEric Biggers 				    const u8 raw_key[POLYVAL_BLOCK_SIZE])
2761f66c52SEric Biggers {
2861f66c52SEric Biggers 	static_assert(ARRAY_SIZE(key->h_powers) == NUM_H_POWERS);
2961f66c52SEric Biggers 	memcpy(&key->h_powers[NUM_H_POWERS - 1], raw_key, POLYVAL_BLOCK_SIZE);
3061f66c52SEric Biggers 	if (static_branch_likely(&have_pmull) && may_use_simd()) {
3161f66c52SEric Biggers 		scoped_ksimd() {
3261f66c52SEric Biggers 			for (int i = NUM_H_POWERS - 2; i >= 0; i--) {
3361f66c52SEric Biggers 				key->h_powers[i] = key->h_powers[i + 1];
3461f66c52SEric Biggers 				polyval_mul_pmull(
3561f66c52SEric Biggers 					&key->h_powers[i],
3661f66c52SEric Biggers 					&key->h_powers[NUM_H_POWERS - 1]);
3761f66c52SEric Biggers 			}
3861f66c52SEric Biggers 		}
3961f66c52SEric Biggers 	} else {
4061f66c52SEric Biggers 		for (int i = NUM_H_POWERS - 2; i >= 0; i--) {
4161f66c52SEric Biggers 			key->h_powers[i] = key->h_powers[i + 1];
4261f66c52SEric Biggers 			polyval_mul_generic(&key->h_powers[i],
4361f66c52SEric Biggers 					    &key->h_powers[NUM_H_POWERS - 1]);
4461f66c52SEric Biggers 		}
4561f66c52SEric Biggers 	}
4661f66c52SEric Biggers }
4761f66c52SEric Biggers 
48a336c01fSEric Biggers static void polyval_mul_arm64(struct polyval_elem *a,
49a336c01fSEric Biggers 			      const struct polyval_elem *b)
50a336c01fSEric Biggers {
51a336c01fSEric Biggers 	if (static_branch_likely(&have_asimd) && may_use_simd()) {
52a336c01fSEric Biggers 		static const u8 zeroes[GHASH_BLOCK_SIZE];
53a336c01fSEric Biggers 
54a336c01fSEric Biggers 		scoped_ksimd() {
55a336c01fSEric Biggers 			if (static_branch_likely(&have_pmull)) {
56a336c01fSEric Biggers 				polyval_mul_pmull(a, b);
57a336c01fSEric Biggers 			} else {
58a336c01fSEric Biggers 				/*
59a336c01fSEric Biggers 				 * Note that this is indeed equivalent to a
60a336c01fSEric Biggers 				 * POLYVAL multiplication, since it takes the
61a336c01fSEric Biggers 				 * accumulator and key in POLYVAL format, and
62a336c01fSEric Biggers 				 * byte-swapping a block of zeroes is a no-op.
63a336c01fSEric Biggers 				 */
64a336c01fSEric Biggers 				pmull_ghash_update_p8(1, a, zeroes, b);
65a336c01fSEric Biggers 			}
66a336c01fSEric Biggers 		}
67a336c01fSEric Biggers 	} else {
68a336c01fSEric Biggers 		polyval_mul_generic(a, b);
69a336c01fSEric Biggers 	}
70a336c01fSEric Biggers }
71a336c01fSEric Biggers 
72a336c01fSEric Biggers #define ghash_mul_arch ghash_mul_arch
73a336c01fSEric Biggers static void ghash_mul_arch(struct polyval_elem *acc,
74a336c01fSEric Biggers 			   const struct ghash_key *key)
75a336c01fSEric Biggers {
76a336c01fSEric Biggers 	polyval_mul_arm64(acc, &key->h);
77a336c01fSEric Biggers }
78a336c01fSEric Biggers 
79b3b6e8f9SEric Biggers #define polyval_mul_arch polyval_mul_arch
8061f66c52SEric Biggers static void polyval_mul_arch(struct polyval_elem *acc,
8161f66c52SEric Biggers 			     const struct polyval_key *key)
8261f66c52SEric Biggers {
83a336c01fSEric Biggers 	polyval_mul_arm64(acc, &key->h_powers[NUM_H_POWERS - 1]);
84a336c01fSEric Biggers }
85a336c01fSEric Biggers 
86a336c01fSEric Biggers #define ghash_blocks_arch ghash_blocks_arch
87a336c01fSEric Biggers static void ghash_blocks_arch(struct polyval_elem *acc,
88a336c01fSEric Biggers 			      const struct ghash_key *key,
89a336c01fSEric Biggers 			      const u8 *data, size_t nblocks)
90a336c01fSEric Biggers {
91a336c01fSEric Biggers 	if (static_branch_likely(&have_asimd) && may_use_simd()) {
9261f66c52SEric Biggers 		scoped_ksimd()
93*d3a5cc5cSEric Biggers 			pmull_ghash_update_p8(nblocks, acc, data, &key->h);
9461f66c52SEric Biggers 	} else {
95a336c01fSEric Biggers 		ghash_blocks_generic(acc, &key->h, data, nblocks);
9661f66c52SEric Biggers 	}
9761f66c52SEric Biggers }
9861f66c52SEric Biggers 
99b3b6e8f9SEric Biggers #define polyval_blocks_arch polyval_blocks_arch
10061f66c52SEric Biggers static void polyval_blocks_arch(struct polyval_elem *acc,
10161f66c52SEric Biggers 				const struct polyval_key *key,
10261f66c52SEric Biggers 				const u8 *data, size_t nblocks)
10361f66c52SEric Biggers {
10461f66c52SEric Biggers 	if (static_branch_likely(&have_pmull) && may_use_simd()) {
10561f66c52SEric Biggers 		scoped_ksimd()
106*d3a5cc5cSEric Biggers 			polyval_blocks_pmull(acc, key, data, nblocks);
10761f66c52SEric Biggers 	} else {
10861f66c52SEric Biggers 		polyval_blocks_generic(acc, &key->h_powers[NUM_H_POWERS - 1],
10961f66c52SEric Biggers 				       data, nblocks);
11061f66c52SEric Biggers 	}
11161f66c52SEric Biggers }
11261f66c52SEric Biggers 
11361f66c52SEric Biggers #define gf128hash_mod_init_arch gf128hash_mod_init_arch
11461f66c52SEric Biggers static void gf128hash_mod_init_arch(void)
11561f66c52SEric Biggers {
116a336c01fSEric Biggers 	if (cpu_have_named_feature(ASIMD)) {
117a336c01fSEric Biggers 		static_branch_enable(&have_asimd);
11861f66c52SEric Biggers 		if (cpu_have_named_feature(PMULL))
11961f66c52SEric Biggers 			static_branch_enable(&have_pmull);
12061f66c52SEric Biggers 	}
121a336c01fSEric Biggers }
122