| 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: &ctx, key); |
| 186 | polyval_update(ctx: &ctx, data, len); |
| 187 | polyval_final(ctx: &ctx, out); |
| 188 | } |
| 189 | |
| 190 | #endif /* _CRYPTO_POLYVAL_H */ |
| 191 | |