/src/nss/lib/freebl/ghash-x86.c
Line | Count | Source |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | #ifdef FREEBL_NO_DEPEND |
6 | | #include "stubs.h" |
7 | | #endif |
8 | | #include "blapii.h" |
9 | | #include "gcm.h" |
10 | | #include "secerr.h" |
11 | | |
12 | | #include <wmmintrin.h> /* clmul */ |
13 | | |
14 | | #define WRITE64(x, bytes) \ |
15 | 0 | (bytes)[0] = (x) >> 56; \ |
16 | 0 | (bytes)[1] = (x) >> 48; \ |
17 | 0 | (bytes)[2] = (x) >> 40; \ |
18 | 0 | (bytes)[3] = (x) >> 32; \ |
19 | 0 | (bytes)[4] = (x) >> 24; \ |
20 | 0 | (bytes)[5] = (x) >> 16; \ |
21 | 0 | (bytes)[6] = (x) >> 8; \ |
22 | 0 | (bytes)[7] = (x); |
23 | | |
24 | | PRBool |
25 | | platform_ghash_support() |
26 | 0 | { |
27 | 0 | return clmul_support(); |
28 | 0 | } |
29 | | |
30 | | SECStatus |
31 | | gcm_HashWrite_hw(gcmHashContext *ghash, unsigned char *outbuf) |
32 | 0 | { |
33 | 0 | uint64_t tmp_out[2]; |
34 | 0 | _mm_storeu_si128((__m128i *)tmp_out, ghash->x); |
35 | | /* maxout must be larger than 16 byte (checked by the caller). */ |
36 | 0 | WRITE64(tmp_out[0], outbuf + 8); |
37 | 0 | WRITE64(tmp_out[1], outbuf); |
38 | 0 | return SECSuccess; |
39 | 0 | } |
40 | | |
41 | | SECStatus |
42 | | gcm_HashMult_hw(gcmHashContext *ghash, const unsigned char *buf, |
43 | | unsigned int count) |
44 | 0 | { |
45 | 0 | size_t i; |
46 | 0 | pre_align __m128i z_high post_align; |
47 | 0 | pre_align __m128i z_low post_align; |
48 | 0 | pre_align __m128i C post_align; |
49 | 0 | pre_align __m128i D post_align; |
50 | 0 | pre_align __m128i E post_align; |
51 | 0 | pre_align __m128i F post_align; |
52 | 0 | pre_align __m128i bin post_align; |
53 | 0 | pre_align __m128i Ci post_align; |
54 | 0 | pre_align __m128i tmp post_align; |
55 | |
|
56 | 0 | for (i = 0; i < count; i++, buf += 16) { |
57 | 0 | bin = _mm_set_epi16(((uint16_t)buf[0] << 8) | buf[1], |
58 | 0 | ((uint16_t)buf[2] << 8) | buf[3], |
59 | 0 | ((uint16_t)buf[4] << 8) | buf[5], |
60 | 0 | ((uint16_t)buf[6] << 8) | buf[7], |
61 | 0 | ((uint16_t)buf[8] << 8) | buf[9], |
62 | 0 | ((uint16_t)buf[10] << 8) | buf[11], |
63 | 0 | ((uint16_t)buf[12] << 8) | buf[13], |
64 | 0 | ((uint16_t)buf[14] << 8) | buf[15]); |
65 | 0 | Ci = _mm_xor_si128(bin, ghash->x); |
66 | | |
67 | | /* Do binary mult ghash->X = Ci * ghash->H. */ |
68 | 0 | C = _mm_clmulepi64_si128(Ci, ghash->h, 0x00); |
69 | 0 | D = _mm_clmulepi64_si128(Ci, ghash->h, 0x11); |
70 | 0 | E = _mm_clmulepi64_si128(Ci, ghash->h, 0x01); |
71 | 0 | F = _mm_clmulepi64_si128(Ci, ghash->h, 0x10); |
72 | 0 | tmp = _mm_xor_si128(E, F); |
73 | 0 | z_high = _mm_xor_si128(tmp, _mm_slli_si128(D, 8)); |
74 | 0 | z_high = _mm_unpackhi_epi64(z_high, D); |
75 | 0 | z_low = _mm_xor_si128(_mm_slli_si128(tmp, 8), C); |
76 | 0 | z_low = _mm_unpackhi_epi64(_mm_slli_si128(C, 8), z_low); |
77 | | |
78 | | /* Shift one to the left (multiply by x) as gcm spec is stupid. */ |
79 | 0 | C = _mm_slli_si128(z_low, 8); |
80 | 0 | E = _mm_srli_epi64(C, 63); |
81 | 0 | D = _mm_slli_si128(z_high, 8); |
82 | 0 | F = _mm_srli_epi64(D, 63); |
83 | | /* Carry over */ |
84 | 0 | C = _mm_srli_si128(z_low, 8); |
85 | 0 | D = _mm_srli_epi64(C, 63); |
86 | 0 | z_low = _mm_or_si128(_mm_slli_epi64(z_low, 1), E); |
87 | 0 | z_high = _mm_or_si128(_mm_or_si128(_mm_slli_epi64(z_high, 1), F), D); |
88 | | |
89 | | /* Reduce */ |
90 | 0 | C = _mm_slli_si128(z_low, 8); |
91 | | /* D = z_low << 127 */ |
92 | 0 | D = _mm_slli_epi64(C, 63); |
93 | | /* E = z_low << 126 */ |
94 | 0 | E = _mm_slli_epi64(C, 62); |
95 | | /* F = z_low << 121 */ |
96 | 0 | F = _mm_slli_epi64(C, 57); |
97 | | /* z_low ^= (z_low << 127) ^ (z_low << 126) ^ (z_low << 121); */ |
98 | 0 | z_low = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(z_low, D), E), F); |
99 | 0 | C = _mm_srli_si128(z_low, 8); |
100 | | /* D = z_low >> 1 */ |
101 | 0 | D = _mm_slli_epi64(C, 63); |
102 | 0 | D = _mm_or_si128(_mm_srli_epi64(z_low, 1), D); |
103 | | /* E = z_low >> 2 */ |
104 | 0 | E = _mm_slli_epi64(C, 62); |
105 | 0 | E = _mm_or_si128(_mm_srli_epi64(z_low, 2), E); |
106 | | /* F = z_low >> 7 */ |
107 | 0 | F = _mm_slli_epi64(C, 57); |
108 | 0 | F = _mm_or_si128(_mm_srli_epi64(z_low, 7), F); |
109 | | /* ghash->x ^= z_low ^ (z_low >> 1) ^ (z_low >> 2) ^ (z_low >> 7); */ |
110 | 0 | ghash->x = _mm_xor_si128(_mm_xor_si128( |
111 | 0 | _mm_xor_si128(_mm_xor_si128(z_high, z_low), D), E), |
112 | 0 | F); |
113 | 0 | } |
114 | 0 | return SECSuccess; |
115 | 0 | } |
116 | | |
117 | | SECStatus |
118 | | gcm_HashInit_hw(gcmHashContext *ghash) |
119 | 0 | { |
120 | 0 | ghash->ghash_mul = gcm_HashMult_hw; |
121 | 0 | ghash->x = _mm_setzero_si128(); |
122 | | /* MSVC requires __m64 to load epi64. */ |
123 | 0 | ghash->h = _mm_set_epi32(ghash->h_high >> 32, (uint32_t)ghash->h_high, |
124 | 0 | ghash->h_low >> 32, (uint32_t)ghash->h_low); |
125 | 0 | ghash->hw = PR_TRUE; |
126 | 0 | return SECSuccess; |
127 | 0 | } |
128 | | |
129 | | SECStatus |
130 | | gcm_HashZeroX_hw(gcmHashContext *ghash) |
131 | 0 | { |
132 | 0 | ghash->x = _mm_setzero_si128(); |
133 | 0 | return SECSuccess; |
134 | 0 | } |