162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * NHPoly1305 - ε-almost-∆-universal hash function for Adiantum
462306a36Sopenharmony_ci * (AVX2 accelerated version)
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright 2018 Google LLC
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <crypto/internal/hash.h>
1062306a36Sopenharmony_ci#include <crypto/internal/simd.h>
1162306a36Sopenharmony_ci#include <crypto/nhpoly1305.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/sizes.h>
1462306a36Sopenharmony_ci#include <asm/simd.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciasmlinkage void nh_avx2(const u32 *key, const u8 *message, size_t message_len,
1762306a36Sopenharmony_ci			__le64 hash[NH_NUM_PASSES]);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic int nhpoly1305_avx2_update(struct shash_desc *desc,
2062306a36Sopenharmony_ci				  const u8 *src, unsigned int srclen)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	if (srclen < 64 || !crypto_simd_usable())
2362306a36Sopenharmony_ci		return crypto_nhpoly1305_update(desc, src, srclen);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	do {
2662306a36Sopenharmony_ci		unsigned int n = min_t(unsigned int, srclen, SZ_4K);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci		kernel_fpu_begin();
2962306a36Sopenharmony_ci		crypto_nhpoly1305_update_helper(desc, src, n, nh_avx2);
3062306a36Sopenharmony_ci		kernel_fpu_end();
3162306a36Sopenharmony_ci		src += n;
3262306a36Sopenharmony_ci		srclen -= n;
3362306a36Sopenharmony_ci	} while (srclen);
3462306a36Sopenharmony_ci	return 0;
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic struct shash_alg nhpoly1305_alg = {
3862306a36Sopenharmony_ci	.base.cra_name		= "nhpoly1305",
3962306a36Sopenharmony_ci	.base.cra_driver_name	= "nhpoly1305-avx2",
4062306a36Sopenharmony_ci	.base.cra_priority	= 300,
4162306a36Sopenharmony_ci	.base.cra_ctxsize	= sizeof(struct nhpoly1305_key),
4262306a36Sopenharmony_ci	.base.cra_module	= THIS_MODULE,
4362306a36Sopenharmony_ci	.digestsize		= POLY1305_DIGEST_SIZE,
4462306a36Sopenharmony_ci	.init			= crypto_nhpoly1305_init,
4562306a36Sopenharmony_ci	.update			= nhpoly1305_avx2_update,
4662306a36Sopenharmony_ci	.final			= crypto_nhpoly1305_final,
4762306a36Sopenharmony_ci	.setkey			= crypto_nhpoly1305_setkey,
4862306a36Sopenharmony_ci	.descsize		= sizeof(struct nhpoly1305_state),
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int __init nhpoly1305_mod_init(void)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	if (!boot_cpu_has(X86_FEATURE_AVX2) ||
5462306a36Sopenharmony_ci	    !boot_cpu_has(X86_FEATURE_OSXSAVE))
5562306a36Sopenharmony_ci		return -ENODEV;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	return crypto_register_shash(&nhpoly1305_alg);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic void __exit nhpoly1305_mod_exit(void)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	crypto_unregister_shash(&nhpoly1305_alg);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cimodule_init(nhpoly1305_mod_init);
6662306a36Sopenharmony_cimodule_exit(nhpoly1305_mod_exit);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciMODULE_DESCRIPTION("NHPoly1305 ε-almost-∆-universal hash function (AVX2-accelerated)");
6962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
7062306a36Sopenharmony_ciMODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
7162306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("nhpoly1305");
7262306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("nhpoly1305-avx2");
73