polyval-ce-glue.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Glue code for POLYVAL using ARMv8 Crypto Extensions
  4. *
  5. * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <[email protected]>
  6. * Copyright (c) 2009 Intel Corp.
  7. * Author: Huang Ying <[email protected]>
  8. * Copyright 2021 Google LLC
  9. */
  10. /*
  11. * Glue code based on ghash-clmulni-intel_glue.c.
  12. *
  13. * This implementation of POLYVAL uses montgomery multiplication accelerated by
  14. * ARMv8 Crypto Extensions instructions to implement the finite field operations.
  15. */
  16. #include <crypto/algapi.h>
  17. #include <crypto/internal/hash.h>
  18. #include <crypto/internal/simd.h>
  19. #include <crypto/polyval.h>
  20. #include <linux/crypto.h>
  21. #include <linux/init.h>
  22. #include <linux/kernel.h>
  23. #include <linux/module.h>
  24. #include <linux/cpufeature.h>
  25. #include <asm/neon.h>
  26. #include <asm/simd.h>
  27. #define NUM_KEY_POWERS 8
  28. struct polyval_tfm_ctx {
  29. /*
  30. * These powers must be in the order h^8, ..., h^1.
  31. */
  32. u8 key_powers[NUM_KEY_POWERS][POLYVAL_BLOCK_SIZE];
  33. };
  34. struct polyval_desc_ctx {
  35. u8 buffer[POLYVAL_BLOCK_SIZE];
  36. u32 bytes;
  37. };
  38. asmlinkage void pmull_polyval_update(const struct polyval_tfm_ctx *keys,
  39. const u8 *in, size_t nblocks, u8 *accumulator);
  40. asmlinkage void pmull_polyval_mul(u8 *op1, const u8 *op2);
  41. static void internal_polyval_update(const struct polyval_tfm_ctx *keys,
  42. const u8 *in, size_t nblocks, u8 *accumulator)
  43. {
  44. if (likely(crypto_simd_usable())) {
  45. kernel_neon_begin();
  46. pmull_polyval_update(keys, in, nblocks, accumulator);
  47. kernel_neon_end();
  48. } else {
  49. polyval_update_non4k(keys->key_powers[NUM_KEY_POWERS-1], in,
  50. nblocks, accumulator);
  51. }
  52. }
  53. static void internal_polyval_mul(u8 *op1, const u8 *op2)
  54. {
  55. if (likely(crypto_simd_usable())) {
  56. kernel_neon_begin();
  57. pmull_polyval_mul(op1, op2);
  58. kernel_neon_end();
  59. } else {
  60. polyval_mul_non4k(op1, op2);
  61. }
  62. }
  63. static int polyval_arm64_setkey(struct crypto_shash *tfm,
  64. const u8 *key, unsigned int keylen)
  65. {
  66. struct polyval_tfm_ctx *tctx = crypto_shash_ctx(tfm);
  67. int i;
  68. if (keylen != POLYVAL_BLOCK_SIZE)
  69. return -EINVAL;
  70. memcpy(tctx->key_powers[NUM_KEY_POWERS-1], key, POLYVAL_BLOCK_SIZE);
  71. for (i = NUM_KEY_POWERS-2; i >= 0; i--) {
  72. memcpy(tctx->key_powers[i], key, POLYVAL_BLOCK_SIZE);
  73. internal_polyval_mul(tctx->key_powers[i],
  74. tctx->key_powers[i+1]);
  75. }
  76. return 0;
  77. }
  78. static int polyval_arm64_init(struct shash_desc *desc)
  79. {
  80. struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
  81. memset(dctx, 0, sizeof(*dctx));
  82. return 0;
  83. }
  84. static int polyval_arm64_update(struct shash_desc *desc,
  85. const u8 *src, unsigned int srclen)
  86. {
  87. struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
  88. const struct polyval_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
  89. u8 *pos;
  90. unsigned int nblocks;
  91. unsigned int n;
  92. if (dctx->bytes) {
  93. n = min(srclen, dctx->bytes);
  94. pos = dctx->buffer + POLYVAL_BLOCK_SIZE - dctx->bytes;
  95. dctx->bytes -= n;
  96. srclen -= n;
  97. while (n--)
  98. *pos++ ^= *src++;
  99. if (!dctx->bytes)
  100. internal_polyval_mul(dctx->buffer,
  101. tctx->key_powers[NUM_KEY_POWERS-1]);
  102. }
  103. while (srclen >= POLYVAL_BLOCK_SIZE) {
  104. /* allow rescheduling every 4K bytes */
  105. nblocks = min(srclen, 4096U) / POLYVAL_BLOCK_SIZE;
  106. internal_polyval_update(tctx, src, nblocks, dctx->buffer);
  107. srclen -= nblocks * POLYVAL_BLOCK_SIZE;
  108. src += nblocks * POLYVAL_BLOCK_SIZE;
  109. }
  110. if (srclen) {
  111. dctx->bytes = POLYVAL_BLOCK_SIZE - srclen;
  112. pos = dctx->buffer;
  113. while (srclen--)
  114. *pos++ ^= *src++;
  115. }
  116. return 0;
  117. }
  118. static int polyval_arm64_final(struct shash_desc *desc, u8 *dst)
  119. {
  120. struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
  121. const struct polyval_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
  122. if (dctx->bytes) {
  123. internal_polyval_mul(dctx->buffer,
  124. tctx->key_powers[NUM_KEY_POWERS-1]);
  125. }
  126. memcpy(dst, dctx->buffer, POLYVAL_BLOCK_SIZE);
  127. return 0;
  128. }
  129. static struct shash_alg polyval_alg = {
  130. .digestsize = POLYVAL_DIGEST_SIZE,
  131. .init = polyval_arm64_init,
  132. .update = polyval_arm64_update,
  133. .final = polyval_arm64_final,
  134. .setkey = polyval_arm64_setkey,
  135. .descsize = sizeof(struct polyval_desc_ctx),
  136. .base = {
  137. .cra_name = "polyval",
  138. .cra_driver_name = "polyval-ce",
  139. .cra_priority = 200,
  140. .cra_blocksize = POLYVAL_BLOCK_SIZE,
  141. .cra_ctxsize = sizeof(struct polyval_tfm_ctx),
  142. .cra_module = THIS_MODULE,
  143. },
  144. };
  145. static int __init polyval_ce_mod_init(void)
  146. {
  147. return crypto_register_shash(&polyval_alg);
  148. }
  149. static void __exit polyval_ce_mod_exit(void)
  150. {
  151. crypto_unregister_shash(&polyval_alg);
  152. }
  153. module_cpu_feature_match(PMULL, polyval_ce_mod_init)
  154. module_exit(polyval_ce_mod_exit);
  155. MODULE_LICENSE("GPL");
  156. MODULE_DESCRIPTION("POLYVAL hash function accelerated by ARMv8 Crypto Extensions");
  157. MODULE_ALIAS_CRYPTO("polyval");
  158. MODULE_ALIAS_CRYPTO("polyval-ce");