161f66c52SEric Biggers /* SPDX-License-Identifier: GPL-2.0-or-later */ 261f66c52SEric Biggers /* 361f66c52SEric Biggers * GF(2^128) polynomial hashing: GHASH and POLYVAL 461f66c52SEric Biggers * 561f66c52SEric Biggers * Copyright 2025 Google LLC 661f66c52SEric Biggers */ 761f66c52SEric Biggers 861f66c52SEric Biggers #ifndef _CRYPTO_GF128HASH_H 961f66c52SEric Biggers #define _CRYPTO_GF128HASH_H 1061f66c52SEric Biggers 11*a78ae6e3SEric Biggers #include <crypto/ghash.h> 1261f66c52SEric Biggers #include <linux/string.h> 1361f66c52SEric Biggers #include <linux/types.h> 1461f66c52SEric Biggers 1561f66c52SEric Biggers #define POLYVAL_BLOCK_SIZE 16 1661f66c52SEric Biggers #define POLYVAL_DIGEST_SIZE 16 1761f66c52SEric Biggers 1861f66c52SEric Biggers /** 1961f66c52SEric Biggers * struct polyval_elem - An element of the POLYVAL finite field 2061f66c52SEric Biggers * @bytes: View of the element as a byte array (unioned with @lo and @hi) 2161f66c52SEric Biggers * @lo: The low 64 terms of the element's polynomial 2261f66c52SEric Biggers * @hi: The high 64 terms of the element's polynomial 2361f66c52SEric Biggers * 2461f66c52SEric Biggers * This represents an element of the finite field GF(2^128), using the POLYVAL 2561f66c52SEric Biggers * convention: little-endian byte order and natural bit order. 2661f66c52SEric Biggers */ 2761f66c52SEric Biggers struct polyval_elem { 2861f66c52SEric Biggers union { 2961f66c52SEric Biggers u8 bytes[POLYVAL_BLOCK_SIZE]; 3061f66c52SEric Biggers struct { 3161f66c52SEric Biggers __le64 lo; 3261f66c52SEric Biggers __le64 hi; 3361f66c52SEric Biggers }; 3461f66c52SEric Biggers }; 3561f66c52SEric Biggers }; 3661f66c52SEric Biggers 3761f66c52SEric Biggers /** 38c417e704SEric Biggers * struct ghash_key - Prepared key for GHASH 39c417e704SEric Biggers * 40c417e704SEric Biggers * Use ghash_preparekey() to initialize this. 41c417e704SEric Biggers */ 42c417e704SEric Biggers struct ghash_key { 4373f315c1SEric Biggers #if defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && defined(CONFIG_PPC64) 4473f315c1SEric Biggers /** @htable: GHASH key format used by the POWER8 assembly code */ 4573f315c1SEric Biggers u64 htable[4][2]; 46efd1d2c8SEric Biggers #elif defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && \ 47efd1d2c8SEric Biggers (defined(CONFIG_RISCV) || defined(CONFIG_S390)) 48af413d71SEric Biggers /** @h_raw: The hash key H, in GHASH format */ 49af413d71SEric Biggers u8 h_raw[GHASH_BLOCK_SIZE]; 5073f315c1SEric Biggers #endif 51c417e704SEric Biggers /** @h: The hash key H, in POLYVAL format */ 52c417e704SEric Biggers struct polyval_elem h; 53c417e704SEric Biggers }; 54c417e704SEric Biggers 55c417e704SEric Biggers /** 5661f66c52SEric Biggers * struct polyval_key - Prepared key for POLYVAL 5761f66c52SEric Biggers * 5861f66c52SEric Biggers * This may contain just the raw key H, or it may contain precomputed key 5961f66c52SEric Biggers * powers, depending on the platform's POLYVAL implementation. Use 6061f66c52SEric Biggers * polyval_preparekey() to initialize this. 6161f66c52SEric Biggers * 6261f66c52SEric Biggers * By H^i we mean H^(i-1) * H * x^-128, with base case H^1 = H. I.e. the 6361f66c52SEric Biggers * exponentiation repeats the POLYVAL dot operation, with its "extra" x^-128. 6461f66c52SEric Biggers */ 6561f66c52SEric Biggers struct polyval_key { 66b3b6e8f9SEric Biggers #if defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && \ 67b3b6e8f9SEric Biggers (defined(CONFIG_ARM64) || defined(CONFIG_X86)) 6861f66c52SEric Biggers /** @h_powers: Powers of the hash key H^8 through H^1 */ 6961f66c52SEric Biggers struct polyval_elem h_powers[8]; 7061f66c52SEric Biggers #else 7161f66c52SEric Biggers /** @h: The hash key H */ 7261f66c52SEric Biggers struct polyval_elem h; 73b3b6e8f9SEric Biggers #endif 7461f66c52SEric Biggers }; 7561f66c52SEric Biggers 7661f66c52SEric Biggers /** 77c417e704SEric Biggers * struct ghash_ctx - Context for computing a GHASH value 78c417e704SEric Biggers * @key: Pointer to the prepared GHASH key. The user of the API is 79c417e704SEric Biggers * responsible for ensuring that the key lives as long as the context. 80c417e704SEric Biggers * @acc: The accumulator. It is stored in POLYVAL format rather than GHASH 81c417e704SEric Biggers * format, since most implementations want it in POLYVAL format. 82c417e704SEric Biggers * @partial: Number of data bytes processed so far modulo GHASH_BLOCK_SIZE 83c417e704SEric Biggers */ 84c417e704SEric Biggers struct ghash_ctx { 85c417e704SEric Biggers const struct ghash_key *key; 86c417e704SEric Biggers struct polyval_elem acc; 87c417e704SEric Biggers size_t partial; 88c417e704SEric Biggers }; 89c417e704SEric Biggers 90c417e704SEric Biggers /** 9161f66c52SEric Biggers * struct polyval_ctx - Context for computing a POLYVAL value 9261f66c52SEric Biggers * @key: Pointer to the prepared POLYVAL key. The user of the API is 9361f66c52SEric Biggers * responsible for ensuring that the key lives as long as the context. 9461f66c52SEric Biggers * @acc: The accumulator 9561f66c52SEric Biggers * @partial: Number of data bytes processed so far modulo POLYVAL_BLOCK_SIZE 9661f66c52SEric Biggers */ 9761f66c52SEric Biggers struct polyval_ctx { 9861f66c52SEric Biggers const struct polyval_key *key; 9961f66c52SEric Biggers struct polyval_elem acc; 10061f66c52SEric Biggers size_t partial; 10161f66c52SEric Biggers }; 10261f66c52SEric Biggers 10361f66c52SEric Biggers /** 104c417e704SEric Biggers * ghash_preparekey() - Prepare a GHASH key 105c417e704SEric Biggers * @key: (output) The key structure to initialize 106c417e704SEric Biggers * @raw_key: The raw hash key 107c417e704SEric Biggers * 108c417e704SEric Biggers * Initialize a GHASH key structure from a raw key. 109c417e704SEric Biggers * 110c417e704SEric Biggers * Context: Any context. 111c417e704SEric Biggers */ 112c417e704SEric Biggers void ghash_preparekey(struct ghash_key *key, 113c417e704SEric Biggers const u8 raw_key[GHASH_BLOCK_SIZE]); 114c417e704SEric Biggers 115c417e704SEric Biggers /** 11661f66c52SEric Biggers * polyval_preparekey() - Prepare a POLYVAL key 11761f66c52SEric Biggers * @key: (output) The key structure to initialize 11861f66c52SEric Biggers * @raw_key: The raw hash key 11961f66c52SEric Biggers * 12061f66c52SEric Biggers * Initialize a POLYVAL key structure from a raw key. This may be a simple 12161f66c52SEric Biggers * copy, or it may involve precomputing powers of the key, depending on the 12261f66c52SEric Biggers * platform's POLYVAL implementation. 12361f66c52SEric Biggers * 12461f66c52SEric Biggers * Context: Any context. 12561f66c52SEric Biggers */ 12661f66c52SEric Biggers void polyval_preparekey(struct polyval_key *key, 12761f66c52SEric Biggers const u8 raw_key[POLYVAL_BLOCK_SIZE]); 12861f66c52SEric Biggers 12961f66c52SEric Biggers /** 130c417e704SEric Biggers * ghash_init() - Initialize a GHASH context for a new message 131c417e704SEric Biggers * @ctx: The context to initialize 132c417e704SEric Biggers * @key: The key to use. Note that a pointer to the key is saved in the 133c417e704SEric Biggers * context, so the key must live at least as long as the context. 134c417e704SEric Biggers */ 135c417e704SEric Biggers static inline void ghash_init(struct ghash_ctx *ctx, 136c417e704SEric Biggers const struct ghash_key *key) 137c417e704SEric Biggers { 138c417e704SEric Biggers *ctx = (struct ghash_ctx){ .key = key }; 139c417e704SEric Biggers } 140c417e704SEric Biggers 141c417e704SEric Biggers /** 14261f66c52SEric Biggers * polyval_init() - Initialize a POLYVAL context for a new message 14361f66c52SEric Biggers * @ctx: The context to initialize 14461f66c52SEric Biggers * @key: The key to use. Note that a pointer to the key is saved in the 14561f66c52SEric Biggers * context, so the key must live at least as long as the context. 14661f66c52SEric Biggers */ 14761f66c52SEric Biggers static inline void polyval_init(struct polyval_ctx *ctx, 14861f66c52SEric Biggers const struct polyval_key *key) 14961f66c52SEric Biggers { 15061f66c52SEric Biggers *ctx = (struct polyval_ctx){ .key = key }; 15161f66c52SEric Biggers } 15261f66c52SEric Biggers 15361f66c52SEric Biggers /** 15461f66c52SEric Biggers * polyval_import_blkaligned() - Import a POLYVAL accumulator value 15561f66c52SEric Biggers * @ctx: The context to initialize 15661f66c52SEric Biggers * @key: The key to import. Note that a pointer to the key is saved in the 15761f66c52SEric Biggers * context, so the key must live at least as long as the context. 15861f66c52SEric Biggers * @acc: The accumulator value to import. 15961f66c52SEric Biggers * 16061f66c52SEric Biggers * This imports an accumulator that was saved by polyval_export_blkaligned(). 16161f66c52SEric Biggers * The same key must be used. 16261f66c52SEric Biggers */ 16361f66c52SEric Biggers static inline void 16461f66c52SEric Biggers polyval_import_blkaligned(struct polyval_ctx *ctx, 16561f66c52SEric Biggers const struct polyval_key *key, 16661f66c52SEric Biggers const struct polyval_elem *acc) 16761f66c52SEric Biggers { 16861f66c52SEric Biggers *ctx = (struct polyval_ctx){ .key = key, .acc = *acc }; 16961f66c52SEric Biggers } 17061f66c52SEric Biggers 17161f66c52SEric Biggers /** 17261f66c52SEric Biggers * polyval_export_blkaligned() - Export a POLYVAL accumulator value 17361f66c52SEric Biggers * @ctx: The context to export the accumulator value from 17461f66c52SEric Biggers * @acc: (output) The exported accumulator value 17561f66c52SEric Biggers * 17661f66c52SEric Biggers * This exports the accumulator from a POLYVAL context. The number of data 17761f66c52SEric Biggers * bytes processed so far must be a multiple of POLYVAL_BLOCK_SIZE. 17861f66c52SEric Biggers */ 17961f66c52SEric Biggers static inline void polyval_export_blkaligned(const struct polyval_ctx *ctx, 18061f66c52SEric Biggers struct polyval_elem *acc) 18161f66c52SEric Biggers { 18261f66c52SEric Biggers *acc = ctx->acc; 18361f66c52SEric Biggers } 18461f66c52SEric Biggers 18561f66c52SEric Biggers /** 186c417e704SEric Biggers * ghash_update() - Update a GHASH context with message data 187c417e704SEric Biggers * @ctx: The context to update; must have been initialized 188c417e704SEric Biggers * @data: The message data 189c417e704SEric Biggers * @len: The data length in bytes. Doesn't need to be block-aligned. 190c417e704SEric Biggers * 191c417e704SEric Biggers * This can be called any number of times. 192c417e704SEric Biggers * 193c417e704SEric Biggers * Context: Any context. 194c417e704SEric Biggers */ 195c417e704SEric Biggers void ghash_update(struct ghash_ctx *ctx, const u8 *data, size_t len); 196c417e704SEric Biggers 197c417e704SEric Biggers /** 19861f66c52SEric Biggers * polyval_update() - Update a POLYVAL context with message data 19961f66c52SEric Biggers * @ctx: The context to update; must have been initialized 20061f66c52SEric Biggers * @data: The message data 20161f66c52SEric Biggers * @len: The data length in bytes. Doesn't need to be block-aligned. 20261f66c52SEric Biggers * 20361f66c52SEric Biggers * This can be called any number of times. 20461f66c52SEric Biggers * 20561f66c52SEric Biggers * Context: Any context. 20661f66c52SEric Biggers */ 20761f66c52SEric Biggers void polyval_update(struct polyval_ctx *ctx, const u8 *data, size_t len); 20861f66c52SEric Biggers 20961f66c52SEric Biggers /** 210c417e704SEric Biggers * ghash_final() - Finish computing a GHASH value 211c417e704SEric Biggers * @ctx: The context to finalize 212c417e704SEric Biggers * @out: The output value 213c417e704SEric Biggers * 214c417e704SEric Biggers * If the total data length isn't a multiple of GHASH_BLOCK_SIZE, then the 215c417e704SEric Biggers * final block is automatically zero-padded. 216c417e704SEric Biggers * 217c417e704SEric Biggers * After finishing, this zeroizes @ctx. So the caller does not need to do it. 218c417e704SEric Biggers * 219c417e704SEric Biggers * Context: Any context. 220c417e704SEric Biggers */ 221c417e704SEric Biggers void ghash_final(struct ghash_ctx *ctx, u8 out[GHASH_BLOCK_SIZE]); 222c417e704SEric Biggers 223c417e704SEric Biggers /** 22461f66c52SEric Biggers * polyval_final() - Finish computing a POLYVAL value 22561f66c52SEric Biggers * @ctx: The context to finalize 22661f66c52SEric Biggers * @out: The output value 22761f66c52SEric Biggers * 22861f66c52SEric Biggers * If the total data length isn't a multiple of POLYVAL_BLOCK_SIZE, then the 22961f66c52SEric Biggers * final block is automatically zero-padded. 23061f66c52SEric Biggers * 23161f66c52SEric Biggers * After finishing, this zeroizes @ctx. So the caller does not need to do it. 23261f66c52SEric Biggers * 23361f66c52SEric Biggers * Context: Any context. 23461f66c52SEric Biggers */ 23561f66c52SEric Biggers void polyval_final(struct polyval_ctx *ctx, u8 out[POLYVAL_BLOCK_SIZE]); 23661f66c52SEric Biggers 23761f66c52SEric Biggers /** 238c417e704SEric Biggers * ghash() - Compute a GHASH value 239c417e704SEric Biggers * @key: The prepared key 240c417e704SEric Biggers * @data: The message data 241c417e704SEric Biggers * @len: The data length in bytes. Doesn't need to be block-aligned. 242c417e704SEric Biggers * @out: The output value 243c417e704SEric Biggers * 244c417e704SEric Biggers * Context: Any context. 245c417e704SEric Biggers */ 246c417e704SEric Biggers static inline void ghash(const struct ghash_key *key, const u8 *data, 247c417e704SEric Biggers size_t len, u8 out[GHASH_BLOCK_SIZE]) 248c417e704SEric Biggers { 249c417e704SEric Biggers struct ghash_ctx ctx; 250c417e704SEric Biggers 251c417e704SEric Biggers ghash_init(&ctx, key); 252c417e704SEric Biggers ghash_update(&ctx, data, len); 253c417e704SEric Biggers ghash_final(&ctx, out); 254c417e704SEric Biggers } 255c417e704SEric Biggers 256c417e704SEric Biggers /** 25761f66c52SEric Biggers * polyval() - Compute a POLYVAL value 25861f66c52SEric Biggers * @key: The prepared key 25961f66c52SEric Biggers * @data: The message data 26061f66c52SEric Biggers * @len: The data length in bytes. Doesn't need to be block-aligned. 26161f66c52SEric Biggers * @out: The output value 26261f66c52SEric Biggers * 26361f66c52SEric Biggers * Context: Any context. 26461f66c52SEric Biggers */ 26561f66c52SEric Biggers static inline void polyval(const struct polyval_key *key, 26661f66c52SEric Biggers const u8 *data, size_t len, 26761f66c52SEric Biggers u8 out[POLYVAL_BLOCK_SIZE]) 26861f66c52SEric Biggers { 26961f66c52SEric Biggers struct polyval_ctx ctx; 27061f66c52SEric Biggers 27161f66c52SEric Biggers polyval_init(&ctx, key); 27261f66c52SEric Biggers polyval_update(&ctx, data, len); 27361f66c52SEric Biggers polyval_final(&ctx, out); 27461f66c52SEric Biggers } 27561f66c52SEric Biggers 27661f66c52SEric Biggers #endif /* _CRYPTO_GF128HASH_H */ 277