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