18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * NHPoly1305 - ε-almost-∆-universal hash function for Adiantum 48c2ecf20Sopenharmony_ci * (ARM64 NEON accelerated version) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2018 Google LLC 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <asm/neon.h> 108c2ecf20Sopenharmony_ci#include <asm/simd.h> 118c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 128c2ecf20Sopenharmony_ci#include <crypto/internal/simd.h> 138c2ecf20Sopenharmony_ci#include <crypto/nhpoly1305.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciasmlinkage void nh_neon(const u32 *key, const u8 *message, size_t message_len, 178c2ecf20Sopenharmony_ci u8 hash[NH_HASH_BYTES]); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* wrapper to avoid indirect call to assembly, which doesn't work with CFI */ 208c2ecf20Sopenharmony_cistatic void _nh_neon(const u32 *key, const u8 *message, size_t message_len, 218c2ecf20Sopenharmony_ci __le64 hash[NH_NUM_PASSES]) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci nh_neon(key, message, message_len, (u8 *)hash); 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int nhpoly1305_neon_update(struct shash_desc *desc, 278c2ecf20Sopenharmony_ci const u8 *src, unsigned int srclen) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci if (srclen < 64 || !crypto_simd_usable()) 308c2ecf20Sopenharmony_ci return crypto_nhpoly1305_update(desc, src, srclen); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci do { 338c2ecf20Sopenharmony_ci unsigned int n = min_t(unsigned int, srclen, SZ_4K); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci kernel_neon_begin(); 368c2ecf20Sopenharmony_ci crypto_nhpoly1305_update_helper(desc, src, n, _nh_neon); 378c2ecf20Sopenharmony_ci kernel_neon_end(); 388c2ecf20Sopenharmony_ci src += n; 398c2ecf20Sopenharmony_ci srclen -= n; 408c2ecf20Sopenharmony_ci } while (srclen); 418c2ecf20Sopenharmony_ci return 0; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic struct shash_alg nhpoly1305_alg = { 458c2ecf20Sopenharmony_ci .base.cra_name = "nhpoly1305", 468c2ecf20Sopenharmony_ci .base.cra_driver_name = "nhpoly1305-neon", 478c2ecf20Sopenharmony_ci .base.cra_priority = 200, 488c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct nhpoly1305_key), 498c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 508c2ecf20Sopenharmony_ci .digestsize = POLY1305_DIGEST_SIZE, 518c2ecf20Sopenharmony_ci .init = crypto_nhpoly1305_init, 528c2ecf20Sopenharmony_ci .update = nhpoly1305_neon_update, 538c2ecf20Sopenharmony_ci .final = crypto_nhpoly1305_final, 548c2ecf20Sopenharmony_ci .setkey = crypto_nhpoly1305_setkey, 558c2ecf20Sopenharmony_ci .descsize = sizeof(struct nhpoly1305_state), 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int __init nhpoly1305_mod_init(void) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci if (!cpu_have_named_feature(ASIMD)) 618c2ecf20Sopenharmony_ci return -ENODEV; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return crypto_register_shash(&nhpoly1305_alg); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic void __exit nhpoly1305_mod_exit(void) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci crypto_unregister_shash(&nhpoly1305_alg); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cimodule_init(nhpoly1305_mod_init); 728c2ecf20Sopenharmony_cimodule_exit(nhpoly1305_mod_exit); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NHPoly1305 ε-almost-∆-universal hash function (NEON-accelerated)"); 758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 768c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eric Biggers <ebiggers@google.com>"); 778c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("nhpoly1305"); 788c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("nhpoly1305-neon"); 79