xref: /linux/include/crypto/polyval.h (revision 37919e239ebb2cba573cca56292f7c39fa6d7415)
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 #else
52 #error "Unhandled arch"
53 #endif
54 #else /* CONFIG_CRYPTO_LIB_POLYVAL_ARCH */
55 	/** @h: The hash key H */
56 	struct polyval_elem h;
57 #endif /* !CONFIG_CRYPTO_LIB_POLYVAL_ARCH */
58 };
59 
60 /**
61  * struct polyval_ctx - Context for computing a POLYVAL value
62  * @key: Pointer to the prepared POLYVAL key.  The user of the API is
63  *	 responsible for ensuring that the key lives as long as the context.
64  * @acc: The accumulator
65  * @partial: Number of data bytes processed so far modulo POLYVAL_BLOCK_SIZE
66  */
67 struct polyval_ctx {
68 	const struct polyval_key *key;
69 	struct polyval_elem acc;
70 	size_t partial;
71 };
72 
73 /**
74  * polyval_preparekey() - Prepare a POLYVAL key
75  * @key: (output) The key structure to initialize
76  * @raw_key: The raw hash key
77  *
78  * Initialize a POLYVAL key structure from a raw key.  This may be a simple
79  * copy, or it may involve precomputing powers of the key, depending on the
80  * platform's POLYVAL implementation.
81  *
82  * Context: Any context.
83  */
84 #ifdef CONFIG_CRYPTO_LIB_POLYVAL_ARCH
85 void polyval_preparekey(struct polyval_key *key,
86 			const u8 raw_key[POLYVAL_BLOCK_SIZE]);
87 
88 #else
89 static inline void polyval_preparekey(struct polyval_key *key,
90 				      const u8 raw_key[POLYVAL_BLOCK_SIZE])
91 {
92 	/* Just a simple copy, so inline it. */
93 	memcpy(key->h.bytes, raw_key, POLYVAL_BLOCK_SIZE);
94 }
95 #endif
96 
97 /**
98  * polyval_init() - Initialize a POLYVAL context for a new message
99  * @ctx: The context to initialize
100  * @key: The key to use.  Note that a pointer to the key is saved in the
101  *	 context, so the key must live at least as long as the context.
102  */
103 static inline void polyval_init(struct polyval_ctx *ctx,
104 				const struct polyval_key *key)
105 {
106 	*ctx = (struct polyval_ctx){ .key = key };
107 }
108 
109 /**
110  * polyval_import_blkaligned() - Import a POLYVAL accumulator value
111  * @ctx: The context to initialize
112  * @key: The key to import.  Note that a pointer to the key is saved in the
113  *	 context, so the key must live at least as long as the context.
114  * @acc: The accumulator value to import.
115  *
116  * This imports an accumulator that was saved by polyval_export_blkaligned().
117  * The same key must be used.
118  */
119 static inline void
120 polyval_import_blkaligned(struct polyval_ctx *ctx,
121 			  const struct polyval_key *key,
122 			  const struct polyval_elem *acc)
123 {
124 	*ctx = (struct polyval_ctx){ .key = key, .acc = *acc };
125 }
126 
127 /**
128  * polyval_export_blkaligned() - Export a POLYVAL accumulator value
129  * @ctx: The context to export the accumulator value from
130  * @acc: (output) The exported accumulator value
131  *
132  * This exports the accumulator from a POLYVAL context.  The number of data
133  * bytes processed so far must be a multiple of POLYVAL_BLOCK_SIZE.
134  */
135 static inline void polyval_export_blkaligned(const struct polyval_ctx *ctx,
136 					     struct polyval_elem *acc)
137 {
138 	*acc = ctx->acc;
139 }
140 
141 /**
142  * polyval_update() - Update a POLYVAL context with message data
143  * @ctx: The context to update; must have been initialized
144  * @data: The message data
145  * @len: The data length in bytes.  Doesn't need to be block-aligned.
146  *
147  * This can be called any number of times.
148  *
149  * Context: Any context.
150  */
151 void polyval_update(struct polyval_ctx *ctx, const u8 *data, size_t len);
152 
153 /**
154  * polyval_final() - Finish computing a POLYVAL value
155  * @ctx: The context to finalize
156  * @out: The output value
157  *
158  * If the total data length isn't a multiple of POLYVAL_BLOCK_SIZE, then the
159  * final block is automatically zero-padded.
160  *
161  * After finishing, this zeroizes @ctx.  So the caller does not need to do it.
162  *
163  * Context: Any context.
164  */
165 void polyval_final(struct polyval_ctx *ctx, u8 out[POLYVAL_BLOCK_SIZE]);
166 
167 /**
168  * polyval() - Compute a POLYVAL value
169  * @key: The prepared key
170  * @data: The message data
171  * @len: The data length in bytes.  Doesn't need to be block-aligned.
172  * @out: The output value
173  *
174  * Context: Any context.
175  */
176 static inline void polyval(const struct polyval_key *key,
177 			   const u8 *data, size_t len,
178 			   u8 out[POLYVAL_BLOCK_SIZE])
179 {
180 	struct polyval_ctx ctx;
181 
182 	polyval_init(&ctx, key);
183 	polyval_update(&ctx, data, len);
184 	polyval_final(&ctx, out);
185 }
186 
187 #endif /* _CRYPTO_POLYVAL_H */
188