xref: /linux/include/crypto/polyval.h (revision 7fc2cd2e4b398c57c9cf961cfea05eadbf34c05c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * POLYVAL library API
4  *
5  * Copyright 2025 Google LLC
6  */
7 
8 #ifndef _CRYPTO_POLYVAL_H
9 #define _CRYPTO_POLYVAL_H
10 
11 #include <linux/string.h>
12 #include <linux/types.h>
13 
14 #define POLYVAL_BLOCK_SIZE	16
15 #define POLYVAL_DIGEST_SIZE	16
16 
17 /**
18  * struct polyval_elem - An element of the POLYVAL finite field
19  * @bytes: View of the element as a byte array (unioned with @lo and @hi)
20  * @lo: The low 64 terms of the element's polynomial
21  * @hi: The high 64 terms of the element's polynomial
22  *
23  * This represents an element of the finite field GF(2^128), using the POLYVAL
24  * convention: little-endian byte order and natural bit order.
25  */
26 struct polyval_elem {
27 	union {
28 		u8 bytes[POLYVAL_BLOCK_SIZE];
29 		struct {
30 			__le64 lo;
31 			__le64 hi;
32 		};
33 	};
34 };
35 
36 /**
37  * struct polyval_key - Prepared key for POLYVAL
38  *
39  * This may contain just the raw key H, or it may contain precomputed key
40  * powers, depending on the platform's POLYVAL implementation.  Use
41  * polyval_preparekey() to initialize this.
42  *
43  * By H^i we mean H^(i-1) * H * x^-128, with base case H^1 = H.  I.e. the
44  * exponentiation repeats the POLYVAL dot operation, with its "extra" x^-128.
45  */
46 struct polyval_key {
47 #ifdef CONFIG_CRYPTO_LIB_POLYVAL_ARCH
48 #ifdef CONFIG_ARM64
49 	/** @h_powers: Powers of the hash key H^8 through H^1 */
50 	struct polyval_elem h_powers[8];
51 #elif defined(CONFIG_X86)
52 	/** @h_powers: Powers of the hash key H^8 through H^1 */
53 	struct polyval_elem h_powers[8];
54 #else
55 #error "Unhandled arch"
56 #endif
57 #else /* CONFIG_CRYPTO_LIB_POLYVAL_ARCH */
58 	/** @h: The hash key H */
59 	struct polyval_elem h;
60 #endif /* !CONFIG_CRYPTO_LIB_POLYVAL_ARCH */
61 };
62 
63 /**
64  * struct polyval_ctx - Context for computing a POLYVAL value
65  * @key: Pointer to the prepared POLYVAL key.  The user of the API is
66  *	 responsible for ensuring that the key lives as long as the context.
67  * @acc: The accumulator
68  * @partial: Number of data bytes processed so far modulo POLYVAL_BLOCK_SIZE
69  */
70 struct polyval_ctx {
71 	const struct polyval_key *key;
72 	struct polyval_elem acc;
73 	size_t partial;
74 };
75 
76 /**
77  * polyval_preparekey() - Prepare a POLYVAL key
78  * @key: (output) The key structure to initialize
79  * @raw_key: The raw hash key
80  *
81  * Initialize a POLYVAL key structure from a raw key.  This may be a simple
82  * copy, or it may involve precomputing powers of the key, depending on the
83  * platform's POLYVAL implementation.
84  *
85  * Context: Any context.
86  */
87 #ifdef CONFIG_CRYPTO_LIB_POLYVAL_ARCH
88 void polyval_preparekey(struct polyval_key *key,
89 			const u8 raw_key[POLYVAL_BLOCK_SIZE]);
90 
91 #else
92 static inline void polyval_preparekey(struct polyval_key *key,
93 				      const u8 raw_key[POLYVAL_BLOCK_SIZE])
94 {
95 	/* Just a simple copy, so inline it. */
96 	memcpy(key->h.bytes, raw_key, POLYVAL_BLOCK_SIZE);
97 }
98 #endif
99 
100 /**
101  * polyval_init() - Initialize a POLYVAL context for a new message
102  * @ctx: The context to initialize
103  * @key: The key to use.  Note that a pointer to the key is saved in the
104  *	 context, so the key must live at least as long as the context.
105  */
106 static inline void polyval_init(struct polyval_ctx *ctx,
107 				const struct polyval_key *key)
108 {
109 	*ctx = (struct polyval_ctx){ .key = key };
110 }
111 
112 /**
113  * polyval_import_blkaligned() - Import a POLYVAL accumulator value
114  * @ctx: The context to initialize
115  * @key: The key to import.  Note that a pointer to the key is saved in the
116  *	 context, so the key must live at least as long as the context.
117  * @acc: The accumulator value to import.
118  *
119  * This imports an accumulator that was saved by polyval_export_blkaligned().
120  * The same key must be used.
121  */
122 static inline void
123 polyval_import_blkaligned(struct polyval_ctx *ctx,
124 			  const struct polyval_key *key,
125 			  const struct polyval_elem *acc)
126 {
127 	*ctx = (struct polyval_ctx){ .key = key, .acc = *acc };
128 }
129 
130 /**
131  * polyval_export_blkaligned() - Export a POLYVAL accumulator value
132  * @ctx: The context to export the accumulator value from
133  * @acc: (output) The exported accumulator value
134  *
135  * This exports the accumulator from a POLYVAL context.  The number of data
136  * bytes processed so far must be a multiple of POLYVAL_BLOCK_SIZE.
137  */
138 static inline void polyval_export_blkaligned(const struct polyval_ctx *ctx,
139 					     struct polyval_elem *acc)
140 {
141 	*acc = ctx->acc;
142 }
143 
144 /**
145  * polyval_update() - Update a POLYVAL context with message data
146  * @ctx: The context to update; must have been initialized
147  * @data: The message data
148  * @len: The data length in bytes.  Doesn't need to be block-aligned.
149  *
150  * This can be called any number of times.
151  *
152  * Context: Any context.
153  */
154 void polyval_update(struct polyval_ctx *ctx, const u8 *data, size_t len);
155 
156 /**
157  * polyval_final() - Finish computing a POLYVAL value
158  * @ctx: The context to finalize
159  * @out: The output value
160  *
161  * If the total data length isn't a multiple of POLYVAL_BLOCK_SIZE, then the
162  * final block is automatically zero-padded.
163  *
164  * After finishing, this zeroizes @ctx.  So the caller does not need to do it.
165  *
166  * Context: Any context.
167  */
168 void polyval_final(struct polyval_ctx *ctx, u8 out[POLYVAL_BLOCK_SIZE]);
169 
170 /**
171  * polyval() - Compute a POLYVAL value
172  * @key: The prepared key
173  * @data: The message data
174  * @len: The data length in bytes.  Doesn't need to be block-aligned.
175  * @out: The output value
176  *
177  * Context: Any context.
178  */
179 static inline void polyval(const struct polyval_key *key,
180 			   const u8 *data, size_t len,
181 			   u8 out[POLYVAL_BLOCK_SIZE])
182 {
183 	struct polyval_ctx ctx;
184 
185 	polyval_init(&ctx, key);
186 	polyval_update(&ctx, data, len);
187 	polyval_final(&ctx, out);
188 }
189 
190 #endif /* _CRYPTO_POLYVAL_H */
191