162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * SM3 Secure Hash Algorithm, AVX assembler accelerated.
462306a36Sopenharmony_ci * specified in: https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2021 Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <crypto/internal/hash.h>
1262306a36Sopenharmony_ci#include <crypto/internal/simd.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/types.h>
1662306a36Sopenharmony_ci#include <crypto/sm3.h>
1762306a36Sopenharmony_ci#include <crypto/sm3_base.h>
1862306a36Sopenharmony_ci#include <asm/simd.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ciasmlinkage void sm3_transform_avx(struct sm3_state *state,
2162306a36Sopenharmony_ci			const u8 *data, int nblocks);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic int sm3_avx_update(struct shash_desc *desc, const u8 *data,
2462306a36Sopenharmony_ci			 unsigned int len)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct sm3_state *sctx = shash_desc_ctx(desc);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (!crypto_simd_usable() ||
2962306a36Sopenharmony_ci			(sctx->count % SM3_BLOCK_SIZE) + len < SM3_BLOCK_SIZE) {
3062306a36Sopenharmony_ci		sm3_update(sctx, data, len);
3162306a36Sopenharmony_ci		return 0;
3262306a36Sopenharmony_ci	}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	/*
3562306a36Sopenharmony_ci	 * Make sure struct sm3_state begins directly with the SM3
3662306a36Sopenharmony_ci	 * 256-bit internal state, as this is what the asm functions expect.
3762306a36Sopenharmony_ci	 */
3862306a36Sopenharmony_ci	BUILD_BUG_ON(offsetof(struct sm3_state, state) != 0);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	kernel_fpu_begin();
4162306a36Sopenharmony_ci	sm3_base_do_update(desc, data, len, sm3_transform_avx);
4262306a36Sopenharmony_ci	kernel_fpu_end();
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return 0;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int sm3_avx_finup(struct shash_desc *desc, const u8 *data,
4862306a36Sopenharmony_ci		      unsigned int len, u8 *out)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	if (!crypto_simd_usable()) {
5162306a36Sopenharmony_ci		struct sm3_state *sctx = shash_desc_ctx(desc);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci		if (len)
5462306a36Sopenharmony_ci			sm3_update(sctx, data, len);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci		sm3_final(sctx, out);
5762306a36Sopenharmony_ci		return 0;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	kernel_fpu_begin();
6162306a36Sopenharmony_ci	if (len)
6262306a36Sopenharmony_ci		sm3_base_do_update(desc, data, len, sm3_transform_avx);
6362306a36Sopenharmony_ci	sm3_base_do_finalize(desc, sm3_transform_avx);
6462306a36Sopenharmony_ci	kernel_fpu_end();
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return sm3_base_finish(desc, out);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int sm3_avx_final(struct shash_desc *desc, u8 *out)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	if (!crypto_simd_usable()) {
7262306a36Sopenharmony_ci		sm3_final(shash_desc_ctx(desc), out);
7362306a36Sopenharmony_ci		return 0;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	kernel_fpu_begin();
7762306a36Sopenharmony_ci	sm3_base_do_finalize(desc, sm3_transform_avx);
7862306a36Sopenharmony_ci	kernel_fpu_end();
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return sm3_base_finish(desc, out);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic struct shash_alg sm3_avx_alg = {
8462306a36Sopenharmony_ci	.digestsize	=	SM3_DIGEST_SIZE,
8562306a36Sopenharmony_ci	.init		=	sm3_base_init,
8662306a36Sopenharmony_ci	.update		=	sm3_avx_update,
8762306a36Sopenharmony_ci	.final		=	sm3_avx_final,
8862306a36Sopenharmony_ci	.finup		=	sm3_avx_finup,
8962306a36Sopenharmony_ci	.descsize	=	sizeof(struct sm3_state),
9062306a36Sopenharmony_ci	.base		=	{
9162306a36Sopenharmony_ci		.cra_name	=	"sm3",
9262306a36Sopenharmony_ci		.cra_driver_name =	"sm3-avx",
9362306a36Sopenharmony_ci		.cra_priority	=	300,
9462306a36Sopenharmony_ci		.cra_blocksize	=	SM3_BLOCK_SIZE,
9562306a36Sopenharmony_ci		.cra_module	=	THIS_MODULE,
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int __init sm3_avx_mod_init(void)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	const char *feature_name;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (!boot_cpu_has(X86_FEATURE_AVX)) {
10462306a36Sopenharmony_ci		pr_info("AVX instruction are not detected.\n");
10562306a36Sopenharmony_ci		return -ENODEV;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (!boot_cpu_has(X86_FEATURE_BMI2)) {
10962306a36Sopenharmony_ci		pr_info("BMI2 instruction are not detected.\n");
11062306a36Sopenharmony_ci		return -ENODEV;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (!cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM,
11462306a36Sopenharmony_ci				&feature_name)) {
11562306a36Sopenharmony_ci		pr_info("CPU feature '%s' is not supported.\n", feature_name);
11662306a36Sopenharmony_ci		return -ENODEV;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return crypto_register_shash(&sm3_avx_alg);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic void __exit sm3_avx_mod_exit(void)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	crypto_unregister_shash(&sm3_avx_alg);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cimodule_init(sm3_avx_mod_init);
12862306a36Sopenharmony_cimodule_exit(sm3_avx_mod_exit);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
13162306a36Sopenharmony_ciMODULE_AUTHOR("Tianjia Zhang <tianjia.zhang@linux.alibaba.com>");
13262306a36Sopenharmony_ciMODULE_DESCRIPTION("SM3 Secure Hash Algorithm, AVX assembler accelerated");
13362306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sm3");
13462306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sm3-avx");
135