/* SPDX-License-Identifier: GPL-2.0-or-later */1/*2* POLYVAL library API3*4* Copyright 2025 Google LLC5*/67#ifndef _CRYPTO_POLYVAL_H8#define _CRYPTO_POLYVAL_H910#include <linux/string.h>11#include <linux/types.h>1213#define POLYVAL_BLOCK_SIZE 1614#define POLYVAL_DIGEST_SIZE 161516/**17* struct polyval_elem - An element of the POLYVAL finite field18* @bytes: View of the element as a byte array (unioned with @lo and @hi)19* @lo: The low 64 terms of the element's polynomial20* @hi: The high 64 terms of the element's polynomial21*22* This represents an element of the finite field GF(2^128), using the POLYVAL23* convention: little-endian byte order and natural bit order.24*/25struct polyval_elem {26union {27u8 bytes[POLYVAL_BLOCK_SIZE];28struct {29__le64 lo;30__le64 hi;31};32};33};3435/**36* struct polyval_key - Prepared key for POLYVAL37*38* This may contain just the raw key H, or it may contain precomputed key39* powers, depending on the platform's POLYVAL implementation. Use40* polyval_preparekey() to initialize this.41*42* By H^i we mean H^(i-1) * H * x^-128, with base case H^1 = H. I.e. the43* exponentiation repeats the POLYVAL dot operation, with its "extra" x^-128.44*/45struct polyval_key {46#ifdef CONFIG_CRYPTO_LIB_POLYVAL_ARCH47#ifdef CONFIG_ARM6448/** @h_powers: Powers of the hash key H^8 through H^1 */49struct polyval_elem h_powers[8];50#elif defined(CONFIG_X86)51/** @h_powers: Powers of the hash key H^8 through H^1 */52struct polyval_elem h_powers[8];53#else54#error "Unhandled arch"55#endif56#else /* CONFIG_CRYPTO_LIB_POLYVAL_ARCH */57/** @h: The hash key H */58struct polyval_elem h;59#endif /* !CONFIG_CRYPTO_LIB_POLYVAL_ARCH */60};6162/**63* struct polyval_ctx - Context for computing a POLYVAL value64* @key: Pointer to the prepared POLYVAL key. The user of the API is65* responsible for ensuring that the key lives as long as the context.66* @acc: The accumulator67* @partial: Number of data bytes processed so far modulo POLYVAL_BLOCK_SIZE68*/69struct polyval_ctx {70const struct polyval_key *key;71struct polyval_elem acc;72size_t partial;73};7475/**76* polyval_preparekey() - Prepare a POLYVAL key77* @key: (output) The key structure to initialize78* @raw_key: The raw hash key79*80* Initialize a POLYVAL key structure from a raw key. This may be a simple81* copy, or it may involve precomputing powers of the key, depending on the82* platform's POLYVAL implementation.83*84* Context: Any context.85*/86#ifdef CONFIG_CRYPTO_LIB_POLYVAL_ARCH87void polyval_preparekey(struct polyval_key *key,88const u8 raw_key[POLYVAL_BLOCK_SIZE]);8990#else91static inline void polyval_preparekey(struct polyval_key *key,92const u8 raw_key[POLYVAL_BLOCK_SIZE])93{94/* Just a simple copy, so inline it. */95memcpy(key->h.bytes, raw_key, POLYVAL_BLOCK_SIZE);96}97#endif9899/**100* polyval_init() - Initialize a POLYVAL context for a new message101* @ctx: The context to initialize102* @key: The key to use. Note that a pointer to the key is saved in the103* context, so the key must live at least as long as the context.104*/105static inline void polyval_init(struct polyval_ctx *ctx,106const struct polyval_key *key)107{108*ctx = (struct polyval_ctx){ .key = key };109}110111/**112* polyval_import_blkaligned() - Import a POLYVAL accumulator value113* @ctx: The context to initialize114* @key: The key to import. Note that a pointer to the key is saved in the115* context, so the key must live at least as long as the context.116* @acc: The accumulator value to import.117*118* This imports an accumulator that was saved by polyval_export_blkaligned().119* The same key must be used.120*/121static inline void122polyval_import_blkaligned(struct polyval_ctx *ctx,123const struct polyval_key *key,124const struct polyval_elem *acc)125{126*ctx = (struct polyval_ctx){ .key = key, .acc = *acc };127}128129/**130* polyval_export_blkaligned() - Export a POLYVAL accumulator value131* @ctx: The context to export the accumulator value from132* @acc: (output) The exported accumulator value133*134* This exports the accumulator from a POLYVAL context. The number of data135* bytes processed so far must be a multiple of POLYVAL_BLOCK_SIZE.136*/137static inline void polyval_export_blkaligned(const struct polyval_ctx *ctx,138struct polyval_elem *acc)139{140*acc = ctx->acc;141}142143/**144* polyval_update() - Update a POLYVAL context with message data145* @ctx: The context to update; must have been initialized146* @data: The message data147* @len: The data length in bytes. Doesn't need to be block-aligned.148*149* This can be called any number of times.150*151* Context: Any context.152*/153void polyval_update(struct polyval_ctx *ctx, const u8 *data, size_t len);154155/**156* polyval_final() - Finish computing a POLYVAL value157* @ctx: The context to finalize158* @out: The output value159*160* If the total data length isn't a multiple of POLYVAL_BLOCK_SIZE, then the161* final block is automatically zero-padded.162*163* After finishing, this zeroizes @ctx. So the caller does not need to do it.164*165* Context: Any context.166*/167void polyval_final(struct polyval_ctx *ctx, u8 out[POLYVAL_BLOCK_SIZE]);168169/**170* polyval() - Compute a POLYVAL value171* @key: The prepared key172* @data: The message data173* @len: The data length in bytes. Doesn't need to be block-aligned.174* @out: The output value175*176* Context: Any context.177*/178static inline void polyval(const struct polyval_key *key,179const u8 *data, size_t len,180u8 out[POLYVAL_BLOCK_SIZE])181{182struct polyval_ctx ctx;183184polyval_init(&ctx, key);185polyval_update(&ctx, data, len);186polyval_final(&ctx, out);187}188189#endif /* _CRYPTO_POLYVAL_H */190191192