Botan 2.19.3
Crypto and TLS for C&
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
14namespace Botan {
15
16namespace SHA1_SSE2_F {
17
18namespace {
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/*
35For each multiple of 4, t, we want to calculate this:
36
37W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
38W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1);
39W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1);
40W[t+3] = rol(W[t] ^ W[t-5] ^ W[t-11] ^ W[t-13], 1);
41
42we'll actually calculate this:
43
44W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
45W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1);
46W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1);
47W[t+3] = rol( 0 ^ W[t-5] ^ W[t-11] ^ W[t-13], 1);
48W[t+3] ^= rol(W[t+0], 1);
49
50the parameters are:
51
52W0 = &W[t-16];
53W1 = &W[t-12];
54W2 = &W[t- 8];
55W3 = &W[t- 4];
56
57and on output:
58prepared = W0 + K
59W0 = 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*/
115inline 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*/
124inline 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*/
133inline 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*/
142inline 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
156BOTAN_FUNC_ISA("sse2")
157void 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 BOTAN_FUNC_ISA(isa)
Definition compiler.h:77
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:65
#define prep00_15(P, W)
Definition sha1_sse2.cpp:25
#define GET_P_32(P, i)
#define prep(prep, XW0, XW1, XW2, XW3, K)
Definition sha1_sse2.cpp:79