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