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