/* SPDX-License-Identifier: GPL-2.0-or-later */1/*2* GF(2^128) polynomial hashing: GHASH and POLYVAL3*4* Copyright 2025 Google LLC5*/67#ifndef _CRYPTO_GF128HASH_H8#define _CRYPTO_GF128HASH_H910#include <crypto/ghash.h>11#include <linux/string.h>12#include <linux/types.h>1314#define POLYVAL_BLOCK_SIZE 1615#define POLYVAL_DIGEST_SIZE 161617/**18* struct polyval_elem - An element of the POLYVAL finite field19* @bytes: View of the element as a byte array (unioned with @lo and @hi)20* @lo: The low 64 terms of the element's polynomial21* @hi: The high 64 terms of the element's polynomial22*23* This represents an element of the finite field GF(2^128), using the POLYVAL24* convention: little-endian byte order and natural bit order.25*/26struct polyval_elem {27union {28u8 bytes[POLYVAL_BLOCK_SIZE];29struct {30__le64 lo;31__le64 hi;32};33};34};3536/**37* struct ghash_key - Prepared key for GHASH38*39* Use ghash_preparekey() to initialize this.40*/41struct ghash_key {42#if defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && defined(CONFIG_PPC64)43/** @htable: GHASH key format used by the POWER8 assembly code */44u64 htable[4][2];45#elif defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && \46(defined(CONFIG_RISCV) || defined(CONFIG_S390))47/** @h_raw: The hash key H, in GHASH format */48u8 h_raw[GHASH_BLOCK_SIZE];49#endif50/** @h: The hash key H, in POLYVAL format */51struct polyval_elem h;52};5354/**55* struct polyval_key - Prepared key for POLYVAL56*57* This may contain just the raw key H, or it may contain precomputed key58* powers, depending on the platform's POLYVAL implementation. Use59* polyval_preparekey() to initialize this.60*61* By H^i we mean H^(i-1) * H * x^-128, with base case H^1 = H. I.e. the62* exponentiation repeats the POLYVAL dot operation, with its "extra" x^-128.63*/64struct polyval_key {65#if defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && \66(defined(CONFIG_ARM64) || defined(CONFIG_X86))67/** @h_powers: Powers of the hash key H^8 through H^1 */68struct polyval_elem h_powers[8];69#else70/** @h: The hash key H */71struct polyval_elem h;72#endif73};7475/**76* struct ghash_ctx - Context for computing a GHASH value77* @key: Pointer to the prepared GHASH key. The user of the API is78* responsible for ensuring that the key lives as long as the context.79* @acc: The accumulator. It is stored in POLYVAL format rather than GHASH80* format, since most implementations want it in POLYVAL format.81* @partial: Number of data bytes processed so far modulo GHASH_BLOCK_SIZE82*/83struct ghash_ctx {84const struct ghash_key *key;85struct polyval_elem acc;86size_t partial;87};8889/**90* struct polyval_ctx - Context for computing a POLYVAL value91* @key: Pointer to the prepared POLYVAL key. The user of the API is92* responsible for ensuring that the key lives as long as the context.93* @acc: The accumulator94* @partial: Number of data bytes processed so far modulo POLYVAL_BLOCK_SIZE95*/96struct polyval_ctx {97const struct polyval_key *key;98struct polyval_elem acc;99size_t partial;100};101102/**103* ghash_preparekey() - Prepare a GHASH key104* @key: (output) The key structure to initialize105* @raw_key: The raw hash key106*107* Initialize a GHASH key structure from a raw key.108*109* Context: Any context.110*/111void ghash_preparekey(struct ghash_key *key,112const u8 raw_key[GHASH_BLOCK_SIZE]);113114/**115* polyval_preparekey() - Prepare a POLYVAL key116* @key: (output) The key structure to initialize117* @raw_key: The raw hash key118*119* Initialize a POLYVAL key structure from a raw key. This may be a simple120* copy, or it may involve precomputing powers of the key, depending on the121* platform's POLYVAL implementation.122*123* Context: Any context.124*/125void polyval_preparekey(struct polyval_key *key,126const u8 raw_key[POLYVAL_BLOCK_SIZE]);127128/**129* ghash_init() - Initialize a GHASH context for a new message130* @ctx: The context to initialize131* @key: The key to use. Note that a pointer to the key is saved in the132* context, so the key must live at least as long as the context.133*/134static inline void ghash_init(struct ghash_ctx *ctx,135const struct ghash_key *key)136{137*ctx = (struct ghash_ctx){ .key = key };138}139140/**141* polyval_init() - Initialize a POLYVAL context for a new message142* @ctx: The context to initialize143* @key: The key to use. Note that a pointer to the key is saved in the144* context, so the key must live at least as long as the context.145*/146static inline void polyval_init(struct polyval_ctx *ctx,147const struct polyval_key *key)148{149*ctx = (struct polyval_ctx){ .key = key };150}151152/**153* polyval_import_blkaligned() - Import a POLYVAL accumulator value154* @ctx: The context to initialize155* @key: The key to import. Note that a pointer to the key is saved in the156* context, so the key must live at least as long as the context.157* @acc: The accumulator value to import.158*159* This imports an accumulator that was saved by polyval_export_blkaligned().160* The same key must be used.161*/162static inline void163polyval_import_blkaligned(struct polyval_ctx *ctx,164const struct polyval_key *key,165const struct polyval_elem *acc)166{167*ctx = (struct polyval_ctx){ .key = key, .acc = *acc };168}169170/**171* polyval_export_blkaligned() - Export a POLYVAL accumulator value172* @ctx: The context to export the accumulator value from173* @acc: (output) The exported accumulator value174*175* This exports the accumulator from a POLYVAL context. The number of data176* bytes processed so far must be a multiple of POLYVAL_BLOCK_SIZE.177*/178static inline void polyval_export_blkaligned(const struct polyval_ctx *ctx,179struct polyval_elem *acc)180{181*acc = ctx->acc;182}183184/**185* ghash_update() - Update a GHASH context with message data186* @ctx: The context to update; must have been initialized187* @data: The message data188* @len: The data length in bytes. Doesn't need to be block-aligned.189*190* This can be called any number of times.191*192* Context: Any context.193*/194void ghash_update(struct ghash_ctx *ctx, const u8 *data, size_t len);195196/**197* polyval_update() - Update a POLYVAL context with message data198* @ctx: The context to update; must have been initialized199* @data: The message data200* @len: The data length in bytes. Doesn't need to be block-aligned.201*202* This can be called any number of times.203*204* Context: Any context.205*/206void polyval_update(struct polyval_ctx *ctx, const u8 *data, size_t len);207208/**209* ghash_final() - Finish computing a GHASH value210* @ctx: The context to finalize211* @out: The output value212*213* If the total data length isn't a multiple of GHASH_BLOCK_SIZE, then the214* final block is automatically zero-padded.215*216* After finishing, this zeroizes @ctx. So the caller does not need to do it.217*218* Context: Any context.219*/220void ghash_final(struct ghash_ctx *ctx, u8 out[GHASH_BLOCK_SIZE]);221222/**223* polyval_final() - Finish computing a POLYVAL value224* @ctx: The context to finalize225* @out: The output value226*227* If the total data length isn't a multiple of POLYVAL_BLOCK_SIZE, then the228* final block is automatically zero-padded.229*230* After finishing, this zeroizes @ctx. So the caller does not need to do it.231*232* Context: Any context.233*/234void polyval_final(struct polyval_ctx *ctx, u8 out[POLYVAL_BLOCK_SIZE]);235236/**237* ghash() - Compute a GHASH value238* @key: The prepared key239* @data: The message data240* @len: The data length in bytes. Doesn't need to be block-aligned.241* @out: The output value242*243* Context: Any context.244*/245static inline void ghash(const struct ghash_key *key, const u8 *data,246size_t len, u8 out[GHASH_BLOCK_SIZE])247{248struct ghash_ctx ctx;249250ghash_init(&ctx, key);251ghash_update(&ctx, data, len);252ghash_final(&ctx, out);253}254255/**256* polyval() - Compute a POLYVAL value257* @key: The prepared key258* @data: The message data259* @len: The data length in bytes. Doesn't need to be block-aligned.260* @out: The output value261*262* Context: Any context.263*/264static inline void polyval(const struct polyval_key *key,265const u8 *data, size_t len,266u8 out[POLYVAL_BLOCK_SIZE])267{268struct polyval_ctx ctx;269270polyval_init(&ctx, key);271polyval_update(&ctx, data, len);272polyval_final(&ctx, out);273}274275#endif /* _CRYPTO_GF128HASH_H */276277278