libgcrypt: Import replacement CRC operations
[grub.git] / grub-core / lib / libgcrypt / cipher / bufhelp.h
1 /* bufhelp.h  -  Some buffer manipulation helpers
2  * Copyright (C) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #ifndef GCRYPT_BUFHELP_H
20 #define GCRYPT_BUFHELP_H
21
22
23 #include "bithelp.h"
24
25
26 #undef BUFHELP_FAST_UNALIGNED_ACCESS
27 #if defined(HAVE_GCC_ATTRIBUTE_PACKED) && \
28     defined(HAVE_GCC_ATTRIBUTE_ALIGNED) && \
29     (defined(__i386__) || defined(__x86_64__) || \
30      (defined(__arm__) && defined(__ARM_FEATURE_UNALIGNED)) || \
31      defined(__aarch64__))
32 /* These architectures are able of unaligned memory accesses and can
33    handle those fast.
34  */
35 # define BUFHELP_FAST_UNALIGNED_ACCESS 1
36 #endif
37
38
39 #ifdef BUFHELP_FAST_UNALIGNED_ACCESS
40 /* Define type with one-byte alignment on architectures with fast unaligned
41    memory accesses.
42  */
43 typedef struct bufhelp_int_s
44 {
45   uintptr_t a;
46 } __attribute__((packed, aligned(1))) bufhelp_int_t;
47 #else
48 /* Define type with default alignment for other architectures (unaligned
49    accessed handled in per byte loops).
50  */
51 typedef struct bufhelp_int_s
52 {
53   uintptr_t a;
54 } bufhelp_int_t;
55 #endif
56
57
58 /* Optimized function for small buffer copying */
59 static inline void
60 buf_cpy(void *_dst, const void *_src, size_t len)
61 {
62 #if __GNUC__ >= 4 && (defined(__x86_64__) || defined(__i386__))
63   /* For AMD64 and i386, memcpy is faster.  */
64   memcpy(_dst, _src, len);
65 #else
66   byte *dst = _dst;
67   const byte *src = _src;
68   bufhelp_int_t *ldst;
69   const bufhelp_int_t *lsrc;
70 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
71   const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
72
73   /* Skip fast processing if buffers are unaligned.  */
74   if (((uintptr_t)dst | (uintptr_t)src) & longmask)
75     goto do_bytes;
76 #endif
77
78   ldst = (bufhelp_int_t *)(void *)dst;
79   lsrc = (const bufhelp_int_t *)(const void *)src;
80
81   for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
82     (ldst++)->a = (lsrc++)->a;
83
84   dst = (byte *)ldst;
85   src = (const byte *)lsrc;
86
87 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
88 do_bytes:
89 #endif
90   /* Handle tail.  */
91   for (; len; len--)
92     *dst++ = *src++;
93 #endif /*__GNUC__ >= 4 && (__x86_64__ || __i386__)*/
94 }
95
96
97 /* Optimized function for buffer xoring */
98 static inline void
99 buf_xor(void *_dst, const void *_src1, const void *_src2, size_t len)
100 {
101   byte *dst = _dst;
102   const byte *src1 = _src1;
103   const byte *src2 = _src2;
104   bufhelp_int_t *ldst;
105   const bufhelp_int_t *lsrc1, *lsrc2;
106 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
107   const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
108
109   /* Skip fast processing if buffers are unaligned.  */
110   if (((uintptr_t)dst | (uintptr_t)src1 | (uintptr_t)src2) & longmask)
111     goto do_bytes;
112 #endif
113
114   ldst = (bufhelp_int_t *)(void *)dst;
115   lsrc1 = (const bufhelp_int_t *)(const void *)src1;
116   lsrc2 = (const bufhelp_int_t *)(const void *)src2;
117
118   for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
119     (ldst++)->a = (lsrc1++)->a ^ (lsrc2++)->a;
120
121   dst = (byte *)ldst;
122   src1 = (const byte *)lsrc1;
123   src2 = (const byte *)lsrc2;
124
125 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
126 do_bytes:
127 #endif
128   /* Handle tail.  */
129   for (; len; len--)
130     *dst++ = *src1++ ^ *src2++;
131 }
132
133
134 /* Optimized function for in-place buffer xoring. */
135 static inline void
136 buf_xor_1(void *_dst, const void *_src, size_t len)
137 {
138   byte *dst = _dst;
139   const byte *src = _src;
140   bufhelp_int_t *ldst;
141   const bufhelp_int_t *lsrc;
142 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
143   const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
144
145   /* Skip fast processing if buffers are unaligned.  */
146   if (((uintptr_t)dst | (uintptr_t)src) & longmask)
147     goto do_bytes;
148 #endif
149
150   ldst = (bufhelp_int_t *)(void *)dst;
151   lsrc = (const bufhelp_int_t *)(const void *)src;
152
153   for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
154     (ldst++)->a ^= (lsrc++)->a;
155
156   dst = (byte *)ldst;
157   src = (const byte *)lsrc;
158
159 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
160 do_bytes:
161 #endif
162   /* Handle tail.  */
163   for (; len; len--)
164     *dst++ ^= *src++;
165 }
166
167
168 /* Optimized function for buffer xoring with two destination buffers.  Used
169    mainly by CFB mode encryption.  */
170 static inline void
171 buf_xor_2dst(void *_dst1, void *_dst2, const void *_src, size_t len)
172 {
173   byte *dst1 = _dst1;
174   byte *dst2 = _dst2;
175   const byte *src = _src;
176   bufhelp_int_t *ldst1, *ldst2;
177   const bufhelp_int_t *lsrc;
178 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
179   const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
180
181   /* Skip fast processing if buffers are unaligned.  */
182   if (((uintptr_t)src | (uintptr_t)dst1 | (uintptr_t)dst2) & longmask)
183     goto do_bytes;
184 #endif
185
186   ldst1 = (bufhelp_int_t *)(void *)dst1;
187   ldst2 = (bufhelp_int_t *)(void *)dst2;
188   lsrc = (const bufhelp_int_t *)(const void *)src;
189
190   for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
191     (ldst1++)->a = ((ldst2++)->a ^= (lsrc++)->a);
192
193   dst1 = (byte *)ldst1;
194   dst2 = (byte *)ldst2;
195   src = (const byte *)lsrc;
196
197 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
198 do_bytes:
199 #endif
200   /* Handle tail.  */
201   for (; len; len--)
202     *dst1++ = (*dst2++ ^= *src++);
203 }
204
205
206 /* Optimized function for combined buffer xoring and copying.  Used by mainly
207    CBC mode decryption.  */
208 static inline void
209 buf_xor_n_copy_2(void *_dst_xor, const void *_src_xor, void *_srcdst_cpy,
210                  const void *_src_cpy, size_t len)
211 {
212   byte *dst_xor = _dst_xor;
213   byte *srcdst_cpy = _srcdst_cpy;
214   const byte *src_xor = _src_xor;
215   const byte *src_cpy = _src_cpy;
216   byte temp;
217   bufhelp_int_t *ldst_xor, *lsrcdst_cpy;
218   const bufhelp_int_t *lsrc_cpy, *lsrc_xor;
219   uintptr_t ltemp;
220 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
221   const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
222
223   /* Skip fast processing if buffers are unaligned.  */
224   if (((uintptr_t)src_cpy | (uintptr_t)src_xor | (uintptr_t)dst_xor |
225        (uintptr_t)srcdst_cpy) & longmask)
226     goto do_bytes;
227 #endif
228
229   ldst_xor = (bufhelp_int_t *)(void *)dst_xor;
230   lsrc_xor = (const bufhelp_int_t *)(void *)src_xor;
231   lsrcdst_cpy = (bufhelp_int_t *)(void *)srcdst_cpy;
232   lsrc_cpy = (const bufhelp_int_t *)(const void *)src_cpy;
233
234   for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
235     {
236       ltemp = (lsrc_cpy++)->a;
237       (ldst_xor++)->a = (lsrcdst_cpy)->a ^ (lsrc_xor++)->a;
238       (lsrcdst_cpy++)->a = ltemp;
239     }
240
241   dst_xor = (byte *)ldst_xor;
242   src_xor = (const byte *)lsrc_xor;
243   srcdst_cpy = (byte *)lsrcdst_cpy;
244   src_cpy = (const byte *)lsrc_cpy;
245
246 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
247 do_bytes:
248 #endif
249   /* Handle tail.  */
250   for (; len; len--)
251     {
252       temp = *src_cpy++;
253       *dst_xor++ = *srcdst_cpy ^ *src_xor++;
254       *srcdst_cpy++ = temp;
255     }
256 }
257
258
259 /* Optimized function for combined buffer xoring and copying.  Used by mainly
260    CFB mode decryption.  */
261 static inline void
262 buf_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src, size_t len)
263 {
264   buf_xor_n_copy_2(_dst_xor, _src, _srcdst_cpy, _src, len);
265 }
266
267
268 /* Constant-time compare of two buffers.  Returns 1 if buffers are equal,
269    and 0 if buffers differ.  */
270 static inline int
271 buf_eq_const(const void *_a, const void *_b, size_t len)
272 {
273   const byte *a = _a;
274   const byte *b = _b;
275   size_t diff, i;
276
277   /* Constant-time compare. */
278   for (i = 0, diff = 0; i < len; i++)
279     diff -= !!(a[i] - b[i]);
280
281   return !diff;
282 }
283
284
285 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
286
287 /* Functions for loading and storing unaligned u32 values of different
288    endianness.  */
289 static inline u32 buf_get_be32(const void *_buf)
290 {
291   const byte *in = _buf;
292   return ((u32)in[0] << 24) | ((u32)in[1] << 16) | \
293          ((u32)in[2] << 8) | (u32)in[3];
294 }
295
296 static inline u32 buf_get_le32(const void *_buf)
297 {
298   const byte *in = _buf;
299   return ((u32)in[3] << 24) | ((u32)in[2] << 16) | \
300          ((u32)in[1] << 8) | (u32)in[0];
301 }
302
303 static inline void buf_put_be32(void *_buf, u32 val)
304 {
305   byte *out = _buf;
306   out[0] = val >> 24;
307   out[1] = val >> 16;
308   out[2] = val >> 8;
309   out[3] = val;
310 }
311
312 static inline void buf_put_le32(void *_buf, u32 val)
313 {
314   byte *out = _buf;
315   out[3] = val >> 24;
316   out[2] = val >> 16;
317   out[1] = val >> 8;
318   out[0] = val;
319 }
320
321
322 /* Functions for loading and storing unaligned u64 values of different
323    endianness.  */
324 static inline u64 buf_get_be64(const void *_buf)
325 {
326   const byte *in = _buf;
327   return ((u64)in[0] << 56) | ((u64)in[1] << 48) | \
328          ((u64)in[2] << 40) | ((u64)in[3] << 32) | \
329          ((u64)in[4] << 24) | ((u64)in[5] << 16) | \
330          ((u64)in[6] << 8) | (u64)in[7];
331 }
332
333 static inline u64 buf_get_le64(const void *_buf)
334 {
335   const byte *in = _buf;
336   return ((u64)in[7] << 56) | ((u64)in[6] << 48) | \
337          ((u64)in[5] << 40) | ((u64)in[4] << 32) | \
338          ((u64)in[3] << 24) | ((u64)in[2] << 16) | \
339          ((u64)in[1] << 8) | (u64)in[0];
340 }
341
342 static inline void buf_put_be64(void *_buf, u64 val)
343 {
344   byte *out = _buf;
345   out[0] = val >> 56;
346   out[1] = val >> 48;
347   out[2] = val >> 40;
348   out[3] = val >> 32;
349   out[4] = val >> 24;
350   out[5] = val >> 16;
351   out[6] = val >> 8;
352   out[7] = val;
353 }
354
355 static inline void buf_put_le64(void *_buf, u64 val)
356 {
357   byte *out = _buf;
358   out[7] = val >> 56;
359   out[6] = val >> 48;
360   out[5] = val >> 40;
361   out[4] = val >> 32;
362   out[3] = val >> 24;
363   out[2] = val >> 16;
364   out[1] = val >> 8;
365   out[0] = val;
366 }
367
368 #else /*BUFHELP_FAST_UNALIGNED_ACCESS*/
369
370 typedef struct bufhelp_u32_s
371 {
372   u32 a;
373 } __attribute__((packed, aligned(1))) bufhelp_u32_t;
374
375 /* Functions for loading and storing unaligned u32 values of different
376    endianness.  */
377 static inline u32 buf_get_be32(const void *_buf)
378 {
379   return be_bswap32(((const bufhelp_u32_t *)_buf)->a);
380 }
381
382 static inline u32 buf_get_le32(const void *_buf)
383 {
384   return le_bswap32(((const bufhelp_u32_t *)_buf)->a);
385 }
386
387 static inline void buf_put_be32(void *_buf, u32 val)
388 {
389   bufhelp_u32_t *out = _buf;
390   out->a = be_bswap32(val);
391 }
392
393 static inline void buf_put_le32(void *_buf, u32 val)
394 {
395   bufhelp_u32_t *out = _buf;
396   out->a = le_bswap32(val);
397 }
398
399
400 typedef struct bufhelp_u64_s
401 {
402   u64 a;
403 } __attribute__((packed, aligned(1))) bufhelp_u64_t;
404
405 /* Functions for loading and storing unaligned u64 values of different
406    endianness.  */
407 static inline u64 buf_get_be64(const void *_buf)
408 {
409   return be_bswap64(((const bufhelp_u64_t *)_buf)->a);
410 }
411
412 static inline u64 buf_get_le64(const void *_buf)
413 {
414   return le_bswap64(((const bufhelp_u64_t *)_buf)->a);
415 }
416
417 static inline void buf_put_be64(void *_buf, u64 val)
418 {
419   bufhelp_u64_t *out = _buf;
420   out->a = be_bswap64(val);
421 }
422
423 static inline void buf_put_le64(void *_buf, u64 val)
424 {
425   bufhelp_u64_t *out = _buf;
426   out->a = le_bswap64(val);
427 }
428
429
430 #endif /*BUFHELP_FAST_UNALIGNED_ACCESS*/
431
432 #endif /*GCRYPT_BUFHELP_H*/