SHA-1/SSSE3: Improve performance on large buffers
[libgcrypt.git] / cipher / bufhelp.h
1 /* bufhelp.h  -  Some buffer manipulation helpers
2  *      Copyright © 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20 #ifndef G10_BUFHELP_H
21 #define G10_BUFHELP_H
22
23 #include <config.h>
24
25 #ifdef HAVE_STDINT_H
26 # include <stdint.h> /* uintptr_t */
27 #elif defined(HAVE_INTTYPES_H)
28 # include <inttypes.h>
29 #else
30 /* In this case, uintptr_t is provided by config.h. */
31 #endif
32
33 #include "bithelp.h"
34
35
36 #if defined(__i386__) || defined(__x86_64__) || \
37     defined(__powerpc__) || defined(__powerpc64__) || \
38     (defined(__arm__) && defined(__ARM_FEATURE_UNALIGNED)) || \
39     defined(__aarch64__)
40 /* These architectures are able of unaligned memory accesses and can
41    handle those fast.
42  */
43 # define BUFHELP_FAST_UNALIGNED_ACCESS 1
44 #endif
45
46
47 /* Optimized function for small buffer copying */
48 static inline void
49 buf_cpy(void *_dst, const void *_src, size_t len)
50 {
51 #if __GNUC__ >= 4 && (defined(__x86_64__) || defined(__i386__))
52   /* For AMD64 and i386, memcpy is faster.  */
53   memcpy(_dst, _src, len);
54 #else
55   byte *dst = _dst;
56   const byte *src = _src;
57   uintptr_t *ldst;
58   const uintptr_t *lsrc;
59 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
60   const unsigned int longmask = sizeof(uintptr_t) - 1;
61
62   /* Skip fast processing if buffers are unaligned.  */
63   if (((uintptr_t)dst | (uintptr_t)src) & longmask)
64     goto do_bytes;
65 #endif
66
67   ldst = (uintptr_t *)(void *)dst;
68   lsrc = (const uintptr_t *)(const void *)src;
69
70   for (; len >= sizeof(uintptr_t); len -= sizeof(uintptr_t))
71     *ldst++ = *lsrc++;
72
73   dst = (byte *)ldst;
74   src = (const byte *)lsrc;
75
76 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
77 do_bytes:
78 #endif
79   /* Handle tail.  */
80   for (; len; len--)
81     *dst++ = *src++;
82 #endif /*__GNUC__ >= 4 && (__x86_64__ || __i386__)*/
83 }
84
85
86 /* Optimized function for buffer xoring */
87 static inline void
88 buf_xor(void *_dst, const void *_src1, const void *_src2, size_t len)
89 {
90   byte *dst = _dst;
91   const byte *src1 = _src1;
92   const byte *src2 = _src2;
93   uintptr_t *ldst;
94   const uintptr_t *lsrc1, *lsrc2;
95 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
96   const unsigned int longmask = sizeof(uintptr_t) - 1;
97
98   /* Skip fast processing if buffers are unaligned.  */
99   if (((uintptr_t)dst | (uintptr_t)src1 | (uintptr_t)src2) & longmask)
100     goto do_bytes;
101 #endif
102
103   ldst = (uintptr_t *)(void *)dst;
104   lsrc1 = (const uintptr_t *)(const void *)src1;
105   lsrc2 = (const uintptr_t *)(const void *)src2;
106
107   for (; len >= sizeof(uintptr_t); len -= sizeof(uintptr_t))
108     *ldst++ = *lsrc1++ ^ *lsrc2++;
109
110   dst = (byte *)ldst;
111   src1 = (const byte *)lsrc1;
112   src2 = (const byte *)lsrc2;
113
114 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
115 do_bytes:
116 #endif
117   /* Handle tail.  */
118   for (; len; len--)
119     *dst++ = *src1++ ^ *src2++;
120 }
121
122
123 /* Optimized function for buffer xoring with two destination buffers.  Used
124    mainly by CFB mode encryption.  */
125 static inline void
126 buf_xor_2dst(void *_dst1, void *_dst2, const void *_src, size_t len)
127 {
128   byte *dst1 = _dst1;
129   byte *dst2 = _dst2;
130   const byte *src = _src;
131   uintptr_t *ldst1, *ldst2;
132   const uintptr_t *lsrc;
133 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
134   const unsigned int longmask = sizeof(uintptr_t) - 1;
135
136   /* Skip fast processing if buffers are unaligned.  */
137   if (((uintptr_t)src | (uintptr_t)dst1 | (uintptr_t)dst2) & longmask)
138     goto do_bytes;
139 #endif
140
141   ldst1 = (uintptr_t *)(void *)dst1;
142   ldst2 = (uintptr_t *)(void *)dst2;
143   lsrc = (const uintptr_t *)(const void *)src;
144
145   for (; len >= sizeof(uintptr_t); len -= sizeof(uintptr_t))
146     *ldst1++ = (*ldst2++ ^= *lsrc++);
147
148   dst1 = (byte *)ldst1;
149   dst2 = (byte *)ldst2;
150   src = (const byte *)lsrc;
151
152 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
153 do_bytes:
154 #endif
155   /* Handle tail.  */
156   for (; len; len--)
157     *dst1++ = (*dst2++ ^= *src++);
158 }
159
160
161 /* Optimized function for combined buffer xoring and copying.  Used by mainly
162    CBC mode decryption.  */
163 static inline void
164 buf_xor_n_copy_2(void *_dst_xor, const void *_src_xor, void *_srcdst_cpy,
165                  const void *_src_cpy, size_t len)
166 {
167   byte *dst_xor = _dst_xor;
168   byte *srcdst_cpy = _srcdst_cpy;
169   const byte *src_xor = _src_xor;
170   const byte *src_cpy = _src_cpy;
171   byte temp;
172   uintptr_t *ldst_xor, *lsrcdst_cpy;
173   const uintptr_t *lsrc_cpy, *lsrc_xor;
174   uintptr_t ltemp;
175 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
176   const unsigned int longmask = sizeof(uintptr_t) - 1;
177
178   /* Skip fast processing if buffers are unaligned.  */
179   if (((uintptr_t)src_cpy | (uintptr_t)src_xor | (uintptr_t)dst_xor |
180        (uintptr_t)srcdst_cpy) & longmask)
181     goto do_bytes;
182 #endif
183
184   ldst_xor = (uintptr_t *)(void *)dst_xor;
185   lsrc_xor = (const uintptr_t *)(void *)src_xor;
186   lsrcdst_cpy = (uintptr_t *)(void *)srcdst_cpy;
187   lsrc_cpy = (const uintptr_t *)(const void *)src_cpy;
188
189   for (; len >= sizeof(uintptr_t); len -= sizeof(uintptr_t))
190     {
191       ltemp = *lsrc_cpy++;
192       *ldst_xor++ = *lsrcdst_cpy ^ *lsrc_xor++;
193       *lsrcdst_cpy++ = ltemp;
194     }
195
196   dst_xor = (byte *)ldst_xor;
197   src_xor = (const byte *)lsrc_xor;
198   srcdst_cpy = (byte *)lsrcdst_cpy;
199   src_cpy = (const byte *)lsrc_cpy;
200
201 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
202 do_bytes:
203 #endif
204   /* Handle tail.  */
205   for (; len; len--)
206     {
207       temp = *src_cpy++;
208       *dst_xor++ = *srcdst_cpy ^ *src_xor++;
209       *srcdst_cpy++ = temp;
210     }
211 }
212
213
214 /* Optimized function for combined buffer xoring and copying.  Used by mainly
215    CFB mode decryption.  */
216 static inline void
217 buf_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src, size_t len)
218 {
219   buf_xor_n_copy_2(_dst_xor, _src, _srcdst_cpy, _src, len);
220 }
221
222
223 /* Constant-time compare of two buffers.  Returns 1 if buffers are equal,
224    and 0 if buffers differ.  */
225 static inline int
226 buf_eq_const(const void *_a, const void *_b, size_t len)
227 {
228   const byte *a = _a;
229   const byte *b = _b;
230   size_t diff, i;
231
232   /* Constant-time compare. */
233   for (i = 0, diff = 0; i < len; i++)
234     diff -= !!(a[i] - b[i]);
235
236   return !diff;
237 }
238
239
240 #ifndef BUFHELP_FAST_UNALIGNED_ACCESS
241
242 /* Functions for loading and storing unaligned u32 values of different
243    endianness.  */
244 static inline u32 buf_get_be32(const void *_buf)
245 {
246   const byte *in = _buf;
247   return ((u32)in[0] << 24) | ((u32)in[1] << 16) | \
248          ((u32)in[2] << 8) | (u32)in[3];
249 }
250
251 static inline u32 buf_get_le32(const void *_buf)
252 {
253   const byte *in = _buf;
254   return ((u32)in[3] << 24) | ((u32)in[2] << 16) | \
255          ((u32)in[1] << 8) | (u32)in[0];
256 }
257
258 static inline void buf_put_be32(void *_buf, u32 val)
259 {
260   byte *out = _buf;
261   out[0] = val >> 24;
262   out[1] = val >> 16;
263   out[2] = val >> 8;
264   out[3] = val;
265 }
266
267 static inline void buf_put_le32(void *_buf, u32 val)
268 {
269   byte *out = _buf;
270   out[3] = val >> 24;
271   out[2] = val >> 16;
272   out[1] = val >> 8;
273   out[0] = val;
274 }
275
276 #ifdef HAVE_U64_TYPEDEF
277 /* Functions for loading and storing unaligned u64 values of different
278    endianness.  */
279 static inline u64 buf_get_be64(const void *_buf)
280 {
281   const byte *in = _buf;
282   return ((u64)in[0] << 56) | ((u64)in[1] << 48) | \
283          ((u64)in[2] << 40) | ((u64)in[3] << 32) | \
284          ((u64)in[4] << 24) | ((u64)in[5] << 16) | \
285          ((u64)in[6] << 8) | (u64)in[7];
286 }
287
288 static inline u64 buf_get_le64(const void *_buf)
289 {
290   const byte *in = _buf;
291   return ((u64)in[7] << 56) | ((u64)in[6] << 48) | \
292          ((u64)in[5] << 40) | ((u64)in[4] << 32) | \
293          ((u64)in[3] << 24) | ((u64)in[2] << 16) | \
294          ((u64)in[1] << 8) | (u64)in[0];
295 }
296
297 static inline void buf_put_be64(void *_buf, u64 val)
298 {
299   byte *out = _buf;
300   out[0] = val >> 56;
301   out[1] = val >> 48;
302   out[2] = val >> 40;
303   out[3] = val >> 32;
304   out[4] = val >> 24;
305   out[5] = val >> 16;
306   out[6] = val >> 8;
307   out[7] = val;
308 }
309
310 static inline void buf_put_le64(void *_buf, u64 val)
311 {
312   byte *out = _buf;
313   out[7] = val >> 56;
314   out[6] = val >> 48;
315   out[5] = val >> 40;
316   out[4] = val >> 32;
317   out[3] = val >> 24;
318   out[2] = val >> 16;
319   out[1] = val >> 8;
320   out[0] = val;
321 }
322 #endif /*HAVE_U64_TYPEDEF*/
323
324 #else /*BUFHELP_FAST_UNALIGNED_ACCESS*/
325
326 /* Functions for loading and storing unaligned u32 values of different
327    endianness.  */
328 static inline u32 buf_get_be32(const void *_buf)
329 {
330   return be_bswap32(*(const u32 *)_buf);
331 }
332
333 static inline u32 buf_get_le32(const void *_buf)
334 {
335   return le_bswap32(*(const u32 *)_buf);
336 }
337
338 static inline void buf_put_be32(void *_buf, u32 val)
339 {
340   u32 *out = _buf;
341   *out = be_bswap32(val);
342 }
343
344 static inline void buf_put_le32(void *_buf, u32 val)
345 {
346   u32 *out = _buf;
347   *out = le_bswap32(val);
348 }
349
350 #ifdef HAVE_U64_TYPEDEF
351 /* Functions for loading and storing unaligned u64 values of different
352    endianness.  */
353 static inline u64 buf_get_be64(const void *_buf)
354 {
355   return be_bswap64(*(const u64 *)_buf);
356 }
357
358 static inline u64 buf_get_le64(const void *_buf)
359 {
360   return le_bswap64(*(const u64 *)_buf);
361 }
362
363 static inline void buf_put_be64(void *_buf, u64 val)
364 {
365   u64 *out = _buf;
366   *out = be_bswap64(val);
367 }
368
369 static inline void buf_put_le64(void *_buf, u64 val)
370 {
371   u64 *out = _buf;
372   *out = le_bswap64(val);
373 }
374 #endif /*HAVE_U64_TYPEDEF*/
375
376 #endif /*BUFHELP_FAST_UNALIGNED_ACCESS*/
377
378 #endif /*G10_BITHELP_H*/