Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * GF(2^128) polynomial hashing: GHASH and POLYVAL
4 *
5 * Copyright 2025 Google LLC
6 */
7
8#ifndef _CRYPTO_GF128HASH_H
9#define _CRYPTO_GF128HASH_H
10
11#include <crypto/ghash.h>
12#include <linux/string.h>
13#include <linux/types.h>
14
15#define POLYVAL_BLOCK_SIZE 16
16#define POLYVAL_DIGEST_SIZE 16
17
18/**
19 * struct polyval_elem - An element of the POLYVAL finite field
20 * @bytes: View of the element as a byte array (unioned with @lo and @hi)
21 * @lo: The low 64 terms of the element's polynomial
22 * @hi: The high 64 terms of the element's polynomial
23 *
24 * This represents an element of the finite field GF(2^128), using the POLYVAL
25 * convention: little-endian byte order and natural bit order.
26 */
27struct polyval_elem {
28 union {
29 u8 bytes[POLYVAL_BLOCK_SIZE];
30 struct {
31 __le64 lo;
32 __le64 hi;
33 };
34 };
35};
36
37/**
38 * struct ghash_key - Prepared key for GHASH
39 *
40 * Use ghash_preparekey() to initialize this.
41 */
42struct ghash_key {
43#if defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && defined(CONFIG_PPC64)
44 /** @htable: GHASH key format used by the POWER8 assembly code */
45 u64 htable[4][2];
46#elif defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && \
47 (defined(CONFIG_RISCV) || defined(CONFIG_S390))
48 /** @h_raw: The hash key H, in GHASH format */
49 u8 h_raw[GHASH_BLOCK_SIZE];
50#endif
51 /** @h: The hash key H, in POLYVAL format */
52 struct polyval_elem h;
53};
54
55/**
56 * struct polyval_key - Prepared key for POLYVAL
57 *
58 * This may contain just the raw key H, or it may contain precomputed key
59 * powers, depending on the platform's POLYVAL implementation. Use
60 * polyval_preparekey() to initialize this.
61 *
62 * By H^i we mean H^(i-1) * H * x^-128, with base case H^1 = H. I.e. the
63 * exponentiation repeats the POLYVAL dot operation, with its "extra" x^-128.
64 */
65struct polyval_key {
66#if defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && \
67 (defined(CONFIG_ARM64) || defined(CONFIG_X86))
68 /** @h_powers: Powers of the hash key H^8 through H^1 */
69 struct polyval_elem h_powers[8];
70#else
71 /** @h: The hash key H */
72 struct polyval_elem h;
73#endif
74};
75
76/**
77 * struct ghash_ctx - Context for computing a GHASH value
78 * @key: Pointer to the prepared GHASH key. The user of the API is
79 * responsible for ensuring that the key lives as long as the context.
80 * @acc: The accumulator. It is stored in POLYVAL format rather than GHASH
81 * format, since most implementations want it in POLYVAL format.
82 * @partial: Number of data bytes processed so far modulo GHASH_BLOCK_SIZE
83 */
84struct ghash_ctx {
85 const struct ghash_key *key;
86 struct polyval_elem acc;
87 size_t partial;
88};
89
90/**
91 * struct polyval_ctx - Context for computing a POLYVAL value
92 * @key: Pointer to the prepared POLYVAL key. The user of the API is
93 * responsible for ensuring that the key lives as long as the context.
94 * @acc: The accumulator
95 * @partial: Number of data bytes processed so far modulo POLYVAL_BLOCK_SIZE
96 */
97struct polyval_ctx {
98 const struct polyval_key *key;
99 struct polyval_elem acc;
100 size_t partial;
101};
102
103/**
104 * ghash_preparekey() - Prepare a GHASH key
105 * @key: (output) The key structure to initialize
106 * @raw_key: The raw hash key
107 *
108 * Initialize a GHASH key structure from a raw key.
109 *
110 * Context: Any context.
111 */
112void ghash_preparekey(struct ghash_key *key,
113 const u8 raw_key[GHASH_BLOCK_SIZE]);
114
115/**
116 * polyval_preparekey() - Prepare a POLYVAL key
117 * @key: (output) The key structure to initialize
118 * @raw_key: The raw hash key
119 *
120 * Initialize a POLYVAL key structure from a raw key. This may be a simple
121 * copy, or it may involve precomputing powers of the key, depending on the
122 * platform's POLYVAL implementation.
123 *
124 * Context: Any context.
125 */
126void polyval_preparekey(struct polyval_key *key,
127 const u8 raw_key[POLYVAL_BLOCK_SIZE]);
128
129/**
130 * ghash_init() - Initialize a GHASH context for a new message
131 * @ctx: The context to initialize
132 * @key: The key to use. Note that a pointer to the key is saved in the
133 * context, so the key must live at least as long as the context.
134 */
135static inline void ghash_init(struct ghash_ctx *ctx,
136 const struct ghash_key *key)
137{
138 *ctx = (struct ghash_ctx){ .key = key };
139}
140
141/**
142 * polyval_init() - Initialize a POLYVAL context for a new message
143 * @ctx: The context to initialize
144 * @key: The key to use. Note that a pointer to the key is saved in the
145 * context, so the key must live at least as long as the context.
146 */
147static inline void polyval_init(struct polyval_ctx *ctx,
148 const struct polyval_key *key)
149{
150 *ctx = (struct polyval_ctx){ .key = key };
151}
152
153/**
154 * polyval_import_blkaligned() - Import a POLYVAL accumulator value
155 * @ctx: The context to initialize
156 * @key: The key to import. Note that a pointer to the key is saved in the
157 * context, so the key must live at least as long as the context.
158 * @acc: The accumulator value to import.
159 *
160 * This imports an accumulator that was saved by polyval_export_blkaligned().
161 * The same key must be used.
162 */
163static inline void
164polyval_import_blkaligned(struct polyval_ctx *ctx,
165 const struct polyval_key *key,
166 const struct polyval_elem *acc)
167{
168 *ctx = (struct polyval_ctx){ .key = key, .acc = *acc };
169}
170
171/**
172 * polyval_export_blkaligned() - Export a POLYVAL accumulator value
173 * @ctx: The context to export the accumulator value from
174 * @acc: (output) The exported accumulator value
175 *
176 * This exports the accumulator from a POLYVAL context. The number of data
177 * bytes processed so far must be a multiple of POLYVAL_BLOCK_SIZE.
178 */
179static inline void polyval_export_blkaligned(const struct polyval_ctx *ctx,
180 struct polyval_elem *acc)
181{
182 *acc = ctx->acc;
183}
184
185/**
186 * ghash_update() - Update a GHASH context with message data
187 * @ctx: The context to update; must have been initialized
188 * @data: The message data
189 * @len: The data length in bytes. Doesn't need to be block-aligned.
190 *
191 * This can be called any number of times.
192 *
193 * Context: Any context.
194 */
195void ghash_update(struct ghash_ctx *ctx, const u8 *data, size_t len);
196
197/**
198 * polyval_update() - Update a POLYVAL context with message data
199 * @ctx: The context to update; must have been initialized
200 * @data: The message data
201 * @len: The data length in bytes. Doesn't need to be block-aligned.
202 *
203 * This can be called any number of times.
204 *
205 * Context: Any context.
206 */
207void polyval_update(struct polyval_ctx *ctx, const u8 *data, size_t len);
208
209/**
210 * ghash_final() - Finish computing a GHASH value
211 * @ctx: The context to finalize
212 * @out: The output value
213 *
214 * If the total data length isn't a multiple of GHASH_BLOCK_SIZE, then the
215 * final block is automatically zero-padded.
216 *
217 * After finishing, this zeroizes @ctx. So the caller does not need to do it.
218 *
219 * Context: Any context.
220 */
221void ghash_final(struct ghash_ctx *ctx, u8 out[GHASH_BLOCK_SIZE]);
222
223/**
224 * polyval_final() - Finish computing a POLYVAL value
225 * @ctx: The context to finalize
226 * @out: The output value
227 *
228 * If the total data length isn't a multiple of POLYVAL_BLOCK_SIZE, then the
229 * final block is automatically zero-padded.
230 *
231 * After finishing, this zeroizes @ctx. So the caller does not need to do it.
232 *
233 * Context: Any context.
234 */
235void polyval_final(struct polyval_ctx *ctx, u8 out[POLYVAL_BLOCK_SIZE]);
236
237/**
238 * ghash() - Compute a GHASH value
239 * @key: The prepared key
240 * @data: The message data
241 * @len: The data length in bytes. Doesn't need to be block-aligned.
242 * @out: The output value
243 *
244 * Context: Any context.
245 */
246static inline void ghash(const struct ghash_key *key, const u8 *data,
247 size_t len, u8 out[GHASH_BLOCK_SIZE])
248{
249 struct ghash_ctx ctx;
250
251 ghash_init(&ctx, key);
252 ghash_update(&ctx, data, len);
253 ghash_final(&ctx, out);
254}
255
256/**
257 * polyval() - Compute a POLYVAL value
258 * @key: The prepared key
259 * @data: The message data
260 * @len: The data length in bytes. Doesn't need to be block-aligned.
261 * @out: The output value
262 *
263 * Context: Any context.
264 */
265static inline void polyval(const struct polyval_key *key,
266 const u8 *data, size_t len,
267 u8 out[POLYVAL_BLOCK_SIZE])
268{
269 struct polyval_ctx ctx;
270
271 polyval_init(&ctx, key);
272 polyval_update(&ctx, data, len);
273 polyval_final(&ctx, out);
274}
275
276#endif /* _CRYPTO_GF128HASH_H */