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
polyval_preparekey(struct polyval_key * key,const u8 raw_key[POLYVAL_BLOCK_SIZE])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 */
polyval_init(struct polyval_ctx * ctx,const struct polyval_key * key)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
polyval_import_blkaligned(struct polyval_ctx * ctx,const struct polyval_key * key,const struct polyval_elem * acc)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 */
polyval_export_blkaligned(const struct polyval_ctx * ctx,struct polyval_elem * acc)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 */
polyval(const struct polyval_key * key,const u8 * data,size_t len,u8 out[POLYVAL_BLOCK_SIZE])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