crypto: polyval-generic - Use API partial block handling
authorHerbert Xu <herbert@gondor.apana.org.au>
Thu, 24 Apr 2025 10:47:30 +0000 (18:47 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Mon, 28 Apr 2025 11:40:54 +0000 (19:40 +0800)
Use the Crypto API partial block handling.

The accelerated export format on x86/arm64 is easier to use so
switch the generic polyval algorithm to use that format instead.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/polyval-generic.c
include/crypto/polyval.h

index 4f98910bcdb589f5c77ab2343a77a2ca8daff9c5..ffd174e75420be20eb0f1514c7705b092faa6425 100644 (file)
  *
  */
 
-#include <linux/unaligned.h>
-#include <crypto/algapi.h>
 #include <crypto/gf128mul.h>
-#include <crypto/polyval.h>
 #include <crypto/internal/hash.h>
-#include <linux/crypto.h>
-#include <linux/init.h>
+#include <crypto/polyval.h>
+#include <crypto/utils.h>
+#include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/string.h>
+#include <linux/unaligned.h>
 
 struct polyval_tfm_ctx {
        struct gf128mul_4k *gf128;
@@ -63,7 +63,6 @@ struct polyval_desc_ctx {
                u8 buffer[POLYVAL_BLOCK_SIZE];
                be128 buffer128;
        };
-       u32 bytes;
 };
 
 static void copy_and_reverse(u8 dst[POLYVAL_BLOCK_SIZE],
@@ -76,46 +75,6 @@ static void copy_and_reverse(u8 dst[POLYVAL_BLOCK_SIZE],
        put_unaligned(swab64(b), (u64 *)&dst[0]);
 }
 
-/*
- * Performs multiplication in the POLYVAL field using the GHASH field as a
- * subroutine.  This function is used as a fallback for hardware accelerated
- * implementations when simd registers are unavailable.
- *
- * Note: This function is not used for polyval-generic, instead we use the 4k
- * lookup table implementation for finite field multiplication.
- */
-void polyval_mul_non4k(u8 *op1, const u8 *op2)
-{
-       be128 a, b;
-
-       // Assume one argument is in Montgomery form and one is not.
-       copy_and_reverse((u8 *)&a, op1);
-       copy_and_reverse((u8 *)&b, op2);
-       gf128mul_x_lle(&a, &a);
-       gf128mul_lle(&a, &b);
-       copy_and_reverse(op1, (u8 *)&a);
-}
-EXPORT_SYMBOL_GPL(polyval_mul_non4k);
-
-/*
- * Perform a POLYVAL update using non4k multiplication.  This function is used
- * as a fallback for hardware accelerated implementations when simd registers
- * are unavailable.
- *
- * Note: This function is not used for polyval-generic, instead we use the 4k
- * lookup table implementation of finite field multiplication.
- */
-void polyval_update_non4k(const u8 *key, const u8 *in,
-                         size_t nblocks, u8 *accumulator)
-{
-       while (nblocks--) {
-               crypto_xor(accumulator, in, POLYVAL_BLOCK_SIZE);
-               polyval_mul_non4k(accumulator, key);
-               in += POLYVAL_BLOCK_SIZE;
-       }
-}
-EXPORT_SYMBOL_GPL(polyval_update_non4k);
-
 static int polyval_setkey(struct crypto_shash *tfm,
                          const u8 *key, unsigned int keylen)
 {
@@ -154,56 +113,53 @@ static int polyval_update(struct shash_desc *desc,
 {
        struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
        const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm);
-       u8 *pos;
        u8 tmp[POLYVAL_BLOCK_SIZE];
-       int n;
-
-       if (dctx->bytes) {
-               n = min(srclen, dctx->bytes);
-               pos = dctx->buffer + dctx->bytes - 1;
-
-               dctx->bytes -= n;
-               srclen -= n;
-
-               while (n--)
-                       *pos-- ^= *src++;
 
-               if (!dctx->bytes)
-                       gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
-       }
-
-       while (srclen >= POLYVAL_BLOCK_SIZE) {
+       do {
                copy_and_reverse(tmp, src);
                crypto_xor(dctx->buffer, tmp, POLYVAL_BLOCK_SIZE);
                gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
                src += POLYVAL_BLOCK_SIZE;
                srclen -= POLYVAL_BLOCK_SIZE;
-       }
+       } while (srclen >= POLYVAL_BLOCK_SIZE);
+
+       return srclen;
+}
 
-       if (srclen) {
-               dctx->bytes = POLYVAL_BLOCK_SIZE - srclen;
-               pos = dctx->buffer + POLYVAL_BLOCK_SIZE - 1;
-               while (srclen--)
-                       *pos-- ^= *src++;
+static int polyval_finup(struct shash_desc *desc, const u8 *src,
+                        unsigned int len, u8 *dst)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
+
+       if (len) {
+               u8 tmp[POLYVAL_BLOCK_SIZE] = {};
+
+               memcpy(tmp, src, len);
+               polyval_update(desc, tmp, POLYVAL_BLOCK_SIZE);
        }
+       copy_and_reverse(dst, dctx->buffer);
+       return 0;
+}
+
+static int polyval_export(struct shash_desc *desc, void *out)
+{
+       struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
 
+       copy_and_reverse(out, dctx->buffer);
        return 0;
 }
 
-static int polyval_final(struct shash_desc *desc, u8 *dst)
+static int polyval_import(struct shash_desc *desc, const void *in)
 {
        struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);
-       const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm);
 
-       if (dctx->bytes)
-               gf128mul_4k_lle(&dctx->buffer128, ctx->gf128);
-       copy_and_reverse(dst, dctx->buffer);
+       copy_and_reverse(dctx->buffer, in);
        return 0;
 }
 
-static void polyval_exit_tfm(struct crypto_tfm *tfm)
+static void polyval_exit_tfm(struct crypto_shash *tfm)
 {
-       struct polyval_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct polyval_tfm_ctx *ctx = crypto_shash_ctx(tfm);
 
        gf128mul_free_4k(ctx->gf128);
 }
@@ -212,17 +168,21 @@ static struct shash_alg polyval_alg = {
        .digestsize     = POLYVAL_DIGEST_SIZE,
        .init           = polyval_init,
        .update         = polyval_update,
-       .final          = polyval_final,
+       .finup          = polyval_finup,
        .setkey         = polyval_setkey,
+       .export         = polyval_export,
+       .import         = polyval_import,
+       .exit_tfm       = polyval_exit_tfm,
+       .statesize      = sizeof(struct polyval_desc_ctx),
        .descsize       = sizeof(struct polyval_desc_ctx),
        .base           = {
                .cra_name               = "polyval",
                .cra_driver_name        = "polyval-generic",
                .cra_priority           = 100,
+               .cra_flags              = CRYPTO_AHASH_ALG_BLOCK_ONLY,
                .cra_blocksize          = POLYVAL_BLOCK_SIZE,
                .cra_ctxsize            = sizeof(struct polyval_tfm_ctx),
                .cra_module             = THIS_MODULE,
-               .cra_exit               = polyval_exit_tfm,
        },
 };
 
index 1d630f371f777eaa0e768aa09ad6f5f14170572f..d2e63743e592cd2c547f5f58b777272e52a96913 100644 (file)
@@ -8,15 +8,7 @@
 #ifndef _CRYPTO_POLYVAL_H
 #define _CRYPTO_POLYVAL_H
 
-#include <linux/types.h>
-#include <linux/crypto.h>
-
 #define POLYVAL_BLOCK_SIZE     16
 #define POLYVAL_DIGEST_SIZE    16
 
-void polyval_mul_non4k(u8 *op1, const u8 *op2);
-
-void polyval_update_non4k(const u8 *key, const u8 *in,
-                         size_t nblocks, u8 *accumulator);
-
 #endif