polyval-clmulni_glue.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Glue code for POLYVAL using PCMULQDQ-NI
  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
  14. * accelerated by PCLMULQDQ-NI to implement the finite field
  15. * operations.
  16. */
  17. #include <crypto/algapi.h>
  18. #include <crypto/internal/hash.h>
  19. #include <crypto/internal/simd.h>
  20. #include <crypto/polyval.h>
  21. #include <linux/crypto.h>
  22. #include <linux/init.h>
  23. #include <linux/kernel.h>
  24. #include <linux/module.h>
  25. #include <asm/cpu_device_id.h>
  26. #include <asm/simd.h>
  27. #define POLYVAL_ALIGN 16
  28. #define POLYVAL_ALIGN_ATTR __aligned(POLYVAL_ALIGN)
  29. #define POLYVAL_ALIGN_EXTRA ((POLYVAL_ALIGN - 1) & ~(CRYPTO_MINALIGN - 1))
  30. #define POLYVAL_CTX_SIZE (sizeof(struct polyval_tfm_ctx) + POLYVAL_ALIGN_EXTRA)
  31. #define NUM_KEY_POWERS 8
  32. struct polyval_tfm_ctx {
  33. /*
  34. * These powers must be in the order h^8, ..., h^1.
  35. */
  36. u8 key_powers[NUM_KEY_POWERS][POLYVAL_BLOCK_SIZE] POLYVAL_ALIGN_ATTR;
  37. };
  38. struct polyval_desc_ctx {
  39. u8 buffer[POLYVAL_BLOCK_SIZE];
  40. u32 bytes;
  41. };
  42. asmlinkage void clmul_polyval_update(const struct polyval_tfm_ctx *keys,
  43. const u8 *in, size_t nblocks, u8 *accumulator);
  44. asmlinkage void clmul_polyval_mul(u8 *op1, const u8 *op2);
  45. static inline struct polyval_tfm_ctx *polyval_tfm_ctx(struct crypto_shash *tfm)
  46. {
  47. return PTR_ALIGN(crypto_shash_ctx(tfm), POLYVAL_ALIGN);
  48. }
  49. static void internal_polyval_update(const struct polyval_tfm_ctx *keys,
  50. const u8 *in, size_t nblocks, u8 *accumulator)
  51. {
  52. if (likely(crypto_simd_usable())) {
  53. kernel_fpu_begin();
  54. clmul_polyval_update(keys, in, nblocks, accumulator);
  55. kernel_fpu_end();
  56. } else {
  57. polyval_update_non4k(keys->key_powers[NUM_KEY_POWERS-1], in,
  58. nblocks, accumulator);
  59. }
  60. }
  61. static void internal_polyval_mul(u8 *op1, const u8 *op2)
  62. {
  63. if (likely(crypto_simd_usable())) {
  64. kernel_fpu_begin();
  65. clmul_polyval_mul(op1, op2);
  66. kernel_fpu_end();
  67. } else {
  68. polyval_mul_non4k(op1, op2);
  69. }
  70. }
  71. static int polyval_x86_setkey(struct crypto_shash *tfm,
  72. const u8 *key, unsigned int keylen)
  73. {
  74. struct polyval_tfm_ctx *tctx = polyval_tfm_ctx(tfm);
  75. int i;
  76. if (keylen != POLYVAL_BLOCK_SIZE)
  77. return -EINVAL;
  78. memcpy(tctx->key_powers[NUM_KEY_POWERS-1], key, POLYVAL_BLOCK_SIZE);
  79. for (i = NUM_KEY_POWERS-2; i >= 0; i--) {
  80. memcpy(tctx->key_powers[i], key, POLYVAL_BLOCK_SIZE);
  81. internal_polyval_mul(tctx->key_powers[i],
  82. tctx->key_powers[i+1]);
  83. }
  84. return 0;
  85. }
  86. static int polyval_x86_init(struct shash_desc *desc)
  87. {
  88. struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
  89. memset(dctx, 0, sizeof(*dctx));
  90. return 0;
  91. }
  92. static int polyval_x86_update(struct shash_desc *desc,
  93. const u8 *src, unsigned int srclen)
  94. {
  95. struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
  96. const struct polyval_tfm_ctx *tctx = polyval_tfm_ctx(desc->tfm);
  97. u8 *pos;
  98. unsigned int nblocks;
  99. unsigned int n;
  100. if (dctx->bytes) {
  101. n = min(srclen, dctx->bytes);
  102. pos = dctx->buffer + POLYVAL_BLOCK_SIZE - dctx->bytes;
  103. dctx->bytes -= n;
  104. srclen -= n;
  105. while (n--)
  106. *pos++ ^= *src++;
  107. if (!dctx->bytes)
  108. internal_polyval_mul(dctx->buffer,
  109. tctx->key_powers[NUM_KEY_POWERS-1]);
  110. }
  111. while (srclen >= POLYVAL_BLOCK_SIZE) {
  112. /* Allow rescheduling every 4K bytes. */
  113. nblocks = min(srclen, 4096U) / POLYVAL_BLOCK_SIZE;
  114. internal_polyval_update(tctx, src, nblocks, dctx->buffer);
  115. srclen -= nblocks * POLYVAL_BLOCK_SIZE;
  116. src += nblocks * POLYVAL_BLOCK_SIZE;
  117. }
  118. if (srclen) {
  119. dctx->bytes = POLYVAL_BLOCK_SIZE - srclen;
  120. pos = dctx->buffer;
  121. while (srclen--)
  122. *pos++ ^= *src++;
  123. }
  124. return 0;
  125. }
  126. static int polyval_x86_final(struct shash_desc *desc, u8 *dst)
  127. {
  128. struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
  129. const struct polyval_tfm_ctx *tctx = polyval_tfm_ctx(desc->tfm);
  130. if (dctx->bytes) {
  131. internal_polyval_mul(dctx->buffer,
  132. tctx->key_powers[NUM_KEY_POWERS-1]);
  133. }
  134. memcpy(dst, dctx->buffer, POLYVAL_BLOCK_SIZE);
  135. return 0;
  136. }
  137. static struct shash_alg polyval_alg = {
  138. .digestsize = POLYVAL_DIGEST_SIZE,
  139. .init = polyval_x86_init,
  140. .update = polyval_x86_update,
  141. .final = polyval_x86_final,
  142. .setkey = polyval_x86_setkey,
  143. .descsize = sizeof(struct polyval_desc_ctx),
  144. .base = {
  145. .cra_name = "polyval",
  146. .cra_driver_name = "polyval-clmulni",
  147. .cra_priority = 200,
  148. .cra_blocksize = POLYVAL_BLOCK_SIZE,
  149. .cra_ctxsize = POLYVAL_CTX_SIZE,
  150. .cra_module = THIS_MODULE,
  151. },
  152. };
  153. __maybe_unused static const struct x86_cpu_id pcmul_cpu_id[] = {
  154. X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL),
  155. {}
  156. };
  157. MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);
  158. static int __init polyval_clmulni_mod_init(void)
  159. {
  160. if (!x86_match_cpu(pcmul_cpu_id))
  161. return -ENODEV;
  162. if (!boot_cpu_has(X86_FEATURE_AVX))
  163. return -ENODEV;
  164. return crypto_register_shash(&polyval_alg);
  165. }
  166. static void __exit polyval_clmulni_mod_exit(void)
  167. {
  168. crypto_unregister_shash(&polyval_alg);
  169. }
  170. module_init(polyval_clmulni_mod_init);
  171. module_exit(polyval_clmulni_mod_exit);
  172. MODULE_LICENSE("GPL");
  173. MODULE_DESCRIPTION("POLYVAL hash function accelerated by PCLMULQDQ-NI");
  174. MODULE_ALIAS_CRYPTO("polyval");
  175. MODULE_ALIAS_CRYPTO("polyval-clmulni");