Botan  2.9.0
Crypto and TLS for C++11
sha1_sse2.cpp
Go to the documentation of this file.
1 /*
2 * SHA-1 using SSE2
3 * Based on public domain code by Dean Gaudet
4 * (http://arctic.org/~dean/crypto/sha1.html)
5 * (C) 2009-2011 Jack Lloyd
6 *
7 * Botan is released under the Simplified BSD License (see license.txt)
8 */
9 
10 #include <botan/sha160.h>
11 #include <botan/rotate.h>
12 #include <emmintrin.h>
13 
14 namespace Botan {
15 
16 namespace SHA1_SSE2_F {
17 
18 namespace {
19 
20 /*
21 * First 16 bytes just need byte swapping. Preparing just means
22 * adding in the round constants.
23 */
24 
25 #define prep00_15(P, W) \
26  do { \
27  W = _mm_shufflehi_epi16(W, _MM_SHUFFLE(2, 3, 0, 1)); \
28  W = _mm_shufflelo_epi16(W, _MM_SHUFFLE(2, 3, 0, 1)); \
29  W = _mm_or_si128(_mm_slli_epi16(W, 8), \
30  _mm_srli_epi16(W, 8)); \
31  P.u128 = _mm_add_epi32(W, K00_19); \
32  } while(0)
33 
34 /*
35 For each multiple of 4, t, we want to calculate this:
36 
37 W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
38 W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1);
39 W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1);
40 W[t+3] = rol(W[t] ^ W[t-5] ^ W[t-11] ^ W[t-13], 1);
41 
42 we'll actually calculate this:
43 
44 W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
45 W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1);
46 W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1);
47 W[t+3] = rol( 0 ^ W[t-5] ^ W[t-11] ^ W[t-13], 1);
48 W[t+3] ^= rol(W[t+0], 1);
49 
50 the parameters are:
51 
52 W0 = &W[t-16];
53 W1 = &W[t-12];
54 W2 = &W[t- 8];
55 W3 = &W[t- 4];
56 
57 and on output:
58 prepared = W0 + K
59 W0 = W[t]..W[t+3]
60 */
61 
62 /* note that there is a step here where i want to do a rol by 1, which
63 * normally would look like this:
64 *
65 * r1 = psrld r0,$31
66 * r0 = pslld r0,$1
67 * r0 = por r0,r1
68 *
69 * but instead i do this:
70 *
71 * r1 = pcmpltd r0,zero
72 * r0 = paddd r0,r0
73 * r0 = psub r0,r1
74 *
75 * because pcmpltd and paddd are available in both MMX units on
76 * efficeon, pentium-m, and opteron but shifts are available in
77 * only one unit.
78 */
79 #define prep(prep, XW0, XW1, XW2, XW3, K) \
80  do { \
81  __m128i r0, r1, r2, r3; \
82  \
83  /* load W[t-4] 16-byte aligned, and shift */ \
84  r3 = _mm_srli_si128((XW3), 4); \
85  r0 = (XW0); \
86  /* get high 64-bits of XW0 into low 64-bits */ \
87  r1 = _mm_shuffle_epi32((XW0), _MM_SHUFFLE(1,0,3,2)); \
88  /* load high 64-bits of r1 */ \
89  r1 = _mm_unpacklo_epi64(r1, (XW1)); \
90  r2 = (XW2); \
91  \
92  r0 = _mm_xor_si128(r1, r0); \
93  r2 = _mm_xor_si128(r3, r2); \
94  r0 = _mm_xor_si128(r2, r0); \
95  /* unrotated W[t]..W[t+2] in r0 ... still need W[t+3] */ \
96  \
97  r2 = _mm_slli_si128(r0, 12); \
98  r1 = _mm_cmplt_epi32(r0, _mm_setzero_si128()); \
99  r0 = _mm_add_epi32(r0, r0); /* shift left by 1 */ \
100  r0 = _mm_sub_epi32(r0, r1); /* r0 has W[t]..W[t+2] */ \
101  \
102  r3 = _mm_srli_epi32(r2, 30); \
103  r2 = _mm_slli_epi32(r2, 2); \
104  \
105  r0 = _mm_xor_si128(r0, r3); \
106  r0 = _mm_xor_si128(r0, r2); /* r0 now has W[t+3] */ \
107  \
108  (XW0) = r0; \
109  (prep).u128 = _mm_add_epi32(r0, K); \
110  } while(0)
111 
112 /*
113 * SHA-160 F1 Function
114 */
115 inline void F1(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg)
116  {
117  E += (D ^ (B & (C ^ D))) + msg + rotl<5>(A);
118  B = rotl<30>(B);
119  }
120 
121 /*
122 * SHA-160 F2 Function
123 */
124 inline void F2(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg)
125  {
126  E += (B ^ C ^ D) + msg + rotl<5>(A);
127  B = rotl<30>(B);
128  }
129 
130 /*
131 * SHA-160 F3 Function
132 */
133 inline void F3(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg)
134  {
135  E += ((B & C) | ((B | C) & D)) + msg + rotl<5>(A);
136  B = rotl<30>(B);
137  }
138 
139 /*
140 * SHA-160 F4 Function
141 */
142 inline void F4(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg)
143  {
144  E += (B ^ C ^ D) + msg + rotl<5>(A);
145  B = rotl<30>(B);
146  }
147 
148 }
149 
150 }
151 
152 /*
153 * SHA-160 Compression Function using SSE for message expansion
154 */
155 //static
156 BOTAN_FUNC_ISA("sse2")
157 void SHA_160::sse2_compress_n(secure_vector<uint32_t>& digest, const uint8_t input[], size_t blocks)
158  {
159  using namespace SHA1_SSE2_F;
160 
161  const __m128i K00_19 = _mm_set1_epi32(0x5A827999);
162  const __m128i K20_39 = _mm_set1_epi32(0x6ED9EBA1);
163  const __m128i K40_59 = _mm_set1_epi32(0x8F1BBCDC);
164  const __m128i K60_79 = _mm_set1_epi32(0xCA62C1D6);
165 
166  uint32_t A = digest[0],
167  B = digest[1],
168  C = digest[2],
169  D = digest[3],
170  E = digest[4];
171 
172  const __m128i* input_mm = reinterpret_cast<const __m128i*>(input);
173 
174  for(size_t i = 0; i != blocks; ++i)
175  {
176  union v4si {
177  uint32_t u32[4];
178  __m128i u128;
179  };
180 
181  v4si P0, P1, P2, P3;
182 
183  __m128i W0 = _mm_loadu_si128(&input_mm[0]);
184  prep00_15(P0, W0);
185 
186  __m128i W1 = _mm_loadu_si128(&input_mm[1]);
187  prep00_15(P1, W1);
188 
189  __m128i W2 = _mm_loadu_si128(&input_mm[2]);
190  prep00_15(P2, W2);
191 
192  __m128i W3 = _mm_loadu_si128(&input_mm[3]);
193  prep00_15(P3, W3);
194 
195  /*
196  Using SSE4; slower on Core2 and Nehalem
197  #define GET_P_32(P, i) _mm_extract_epi32(P.u128, i)
198 
199  Much slower on all tested platforms
200  #define GET_P_32(P,i) _mm_cvtsi128_si32(_mm_srli_si128(P.u128, i*4))
201  */
202 
203 #define GET_P_32(P, i) P.u32[i]
204 
205  F1(A, B, C, D, E, GET_P_32(P0, 0));
206  F1(E, A, B, C, D, GET_P_32(P0, 1));
207  F1(D, E, A, B, C, GET_P_32(P0, 2));
208  F1(C, D, E, A, B, GET_P_32(P0, 3));
209  prep(P0, W0, W1, W2, W3, K00_19);
210 
211  F1(B, C, D, E, A, GET_P_32(P1, 0));
212  F1(A, B, C, D, E, GET_P_32(P1, 1));
213  F1(E, A, B, C, D, GET_P_32(P1, 2));
214  F1(D, E, A, B, C, GET_P_32(P1, 3));
215  prep(P1, W1, W2, W3, W0, K20_39);
216 
217  F1(C, D, E, A, B, GET_P_32(P2, 0));
218  F1(B, C, D, E, A, GET_P_32(P2, 1));
219  F1(A, B, C, D, E, GET_P_32(P2, 2));
220  F1(E, A, B, C, D, GET_P_32(P2, 3));
221  prep(P2, W2, W3, W0, W1, K20_39);
222 
223  F1(D, E, A, B, C, GET_P_32(P3, 0));
224  F1(C, D, E, A, B, GET_P_32(P3, 1));
225  F1(B, C, D, E, A, GET_P_32(P3, 2));
226  F1(A, B, C, D, E, GET_P_32(P3, 3));
227  prep(P3, W3, W0, W1, W2, K20_39);
228 
229  F1(E, A, B, C, D, GET_P_32(P0, 0));
230  F1(D, E, A, B, C, GET_P_32(P0, 1));
231  F1(C, D, E, A, B, GET_P_32(P0, 2));
232  F1(B, C, D, E, A, GET_P_32(P0, 3));
233  prep(P0, W0, W1, W2, W3, K20_39);
234 
235  F2(A, B, C, D, E, GET_P_32(P1, 0));
236  F2(E, A, B, C, D, GET_P_32(P1, 1));
237  F2(D, E, A, B, C, GET_P_32(P1, 2));
238  F2(C, D, E, A, B, GET_P_32(P1, 3));
239  prep(P1, W1, W2, W3, W0, K20_39);
240 
241  F2(B, C, D, E, A, GET_P_32(P2, 0));
242  F2(A, B, C, D, E, GET_P_32(P2, 1));
243  F2(E, A, B, C, D, GET_P_32(P2, 2));
244  F2(D, E, A, B, C, GET_P_32(P2, 3));
245  prep(P2, W2, W3, W0, W1, K40_59);
246 
247  F2(C, D, E, A, B, GET_P_32(P3, 0));
248  F2(B, C, D, E, A, GET_P_32(P3, 1));
249  F2(A, B, C, D, E, GET_P_32(P3, 2));
250  F2(E, A, B, C, D, GET_P_32(P3, 3));
251  prep(P3, W3, W0, W1, W2, K40_59);
252 
253  F2(D, E, A, B, C, GET_P_32(P0, 0));
254  F2(C, D, E, A, B, GET_P_32(P0, 1));
255  F2(B, C, D, E, A, GET_P_32(P0, 2));
256  F2(A, B, C, D, E, GET_P_32(P0, 3));
257  prep(P0, W0, W1, W2, W3, K40_59);
258 
259  F2(E, A, B, C, D, GET_P_32(P1, 0));
260  F2(D, E, A, B, C, GET_P_32(P1, 1));
261  F2(C, D, E, A, B, GET_P_32(P1, 2));
262  F2(B, C, D, E, A, GET_P_32(P1, 3));
263  prep(P1, W1, W2, W3, W0, K40_59);
264 
265  F3(A, B, C, D, E, GET_P_32(P2, 0));
266  F3(E, A, B, C, D, GET_P_32(P2, 1));
267  F3(D, E, A, B, C, GET_P_32(P2, 2));
268  F3(C, D, E, A, B, GET_P_32(P2, 3));
269  prep(P2, W2, W3, W0, W1, K40_59);
270 
271  F3(B, C, D, E, A, GET_P_32(P3, 0));
272  F3(A, B, C, D, E, GET_P_32(P3, 1));
273  F3(E, A, B, C, D, GET_P_32(P3, 2));
274  F3(D, E, A, B, C, GET_P_32(P3, 3));
275  prep(P3, W3, W0, W1, W2, K60_79);
276 
277  F3(C, D, E, A, B, GET_P_32(P0, 0));
278  F3(B, C, D, E, A, GET_P_32(P0, 1));
279  F3(A, B, C, D, E, GET_P_32(P0, 2));
280  F3(E, A, B, C, D, GET_P_32(P0, 3));
281  prep(P0, W0, W1, W2, W3, K60_79);
282 
283  F3(D, E, A, B, C, GET_P_32(P1, 0));
284  F3(C, D, E, A, B, GET_P_32(P1, 1));
285  F3(B, C, D, E, A, GET_P_32(P1, 2));
286  F3(A, B, C, D, E, GET_P_32(P1, 3));
287  prep(P1, W1, W2, W3, W0, K60_79);
288 
289  F3(E, A, B, C, D, GET_P_32(P2, 0));
290  F3(D, E, A, B, C, GET_P_32(P2, 1));
291  F3(C, D, E, A, B, GET_P_32(P2, 2));
292  F3(B, C, D, E, A, GET_P_32(P2, 3));
293  prep(P2, W2, W3, W0, W1, K60_79);
294 
295  F4(A, B, C, D, E, GET_P_32(P3, 0));
296  F4(E, A, B, C, D, GET_P_32(P3, 1));
297  F4(D, E, A, B, C, GET_P_32(P3, 2));
298  F4(C, D, E, A, B, GET_P_32(P3, 3));
299  prep(P3, W3, W0, W1, W2, K60_79);
300 
301  F4(B, C, D, E, A, GET_P_32(P0, 0));
302  F4(A, B, C, D, E, GET_P_32(P0, 1));
303  F4(E, A, B, C, D, GET_P_32(P0, 2));
304  F4(D, E, A, B, C, GET_P_32(P0, 3));
305 
306  F4(C, D, E, A, B, GET_P_32(P1, 0));
307  F4(B, C, D, E, A, GET_P_32(P1, 1));
308  F4(A, B, C, D, E, GET_P_32(P1, 2));
309  F4(E, A, B, C, D, GET_P_32(P1, 3));
310 
311  F4(D, E, A, B, C, GET_P_32(P2, 0));
312  F4(C, D, E, A, B, GET_P_32(P2, 1));
313  F4(B, C, D, E, A, GET_P_32(P2, 2));
314  F4(A, B, C, D, E, GET_P_32(P2, 3));
315 
316  F4(E, A, B, C, D, GET_P_32(P3, 0));
317  F4(D, E, A, B, C, GET_P_32(P3, 1));
318  F4(C, D, E, A, B, GET_P_32(P3, 2));
319  F4(B, C, D, E, A, GET_P_32(P3, 3));
320 
321  A = (digest[0] += A);
322  B = (digest[1] += B);
323  C = (digest[2] += C);
324  D = (digest[3] += D);
325  E = (digest[4] += E);
326 
327  input_mm += (64 / 16);
328  }
329 
330 #undef GET_P_32
331  }
332 
333 #undef prep00_15
334 #undef prep
335 
336 }
#define prep00_15(P, W)
Definition: sha1_sse2.cpp:25
#define prep(prep, XW0, XW1, XW2, XW3, K)
Definition: sha1_sse2.cpp:79
#define BOTAN_FUNC_ISA(isa)
Definition: compiler.h:71
Definition: alg_id.cpp:13
#define GET_P_32(P, i)
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65