You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sse42.c 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*-
  2. * Copyright 2017 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*-
  17. Copyright (c) 2013-2015, Alfred Klomp
  18. Copyright (c) 2016, Vsevolod Stakhov
  19. All rights reserved.
  20. Redistribution and use in source and binary forms, with or without
  21. modification, are permitted provided that the following conditions are
  22. met:
  23. - Redistributions of source code must retain the above copyright notice,
  24. this list of conditions and the following disclaimer.
  25. - Redistributions in binary form must reproduce the above copyright
  26. notice, this list of conditions and the following disclaimer in the
  27. documentation and/or other materials provided with the distribution.
  28. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  29. IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  30. TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  31. PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  32. HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  33. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  34. TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  35. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  36. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  37. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  38. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  39. */
  40. #include "config.h"
  41. #include "cryptobox.h"
  42. extern const uint8_t base64_table_dec[256];
  43. #ifdef RSPAMD_HAS_TARGET_ATTR
  44. #if defined(__GNUC__) && !defined(__clang__)
  45. #pragma GCC push_options
  46. #pragma GCC target("sse4.2")
  47. #endif
  48. #ifndef __SSE2__
  49. #define __SSE2__
  50. #endif
  51. #ifndef __SSE__
  52. #define __SSE__
  53. #endif
  54. #ifndef __SSE4_2__
  55. #define __SSE4_2__
  56. #endif
  57. #ifndef __SSE4_1__
  58. #define __SSE4_1__
  59. #endif
  60. #ifndef __SSEE3__
  61. #define __SSEE3__
  62. #endif
  63. #include <xmmintrin.h>
  64. #include <nmmintrin.h>
  65. static inline __m128i
  66. dec_reshuffle (__m128i in) __attribute__((__target__("sse4.2")));
  67. static inline __m128i dec_reshuffle (__m128i in)
  68. {
  69. // Mask in a single byte per shift:
  70. const __m128i maskB2 = _mm_set1_epi32(0x003F0000);
  71. const __m128i maskB1 = _mm_set1_epi32(0x00003F00);
  72. // Pack bytes together:
  73. __m128i out = _mm_srli_epi32(in, 16);
  74. out = _mm_or_si128(out, _mm_srli_epi32(_mm_and_si128(in, maskB2), 2));
  75. out = _mm_or_si128(out, _mm_slli_epi32(_mm_and_si128(in, maskB1), 12));
  76. out = _mm_or_si128(out, _mm_slli_epi32(in, 26));
  77. // Reshuffle and repack into 12-byte output format:
  78. return _mm_shuffle_epi8(out, _mm_setr_epi8(
  79. 3, 2, 1,
  80. 7, 6, 5,
  81. 11, 10, 9,
  82. 15, 14, 13,
  83. -1, -1, -1, -1));
  84. }
  85. #define CMPGT(s,n) _mm_cmpgt_epi8((s), _mm_set1_epi8(n))
  86. #define INNER_LOOP_SSE42 \
  87. while (inlen >= 24) { \
  88. __m128i str = _mm_loadu_si128((__m128i *)c); \
  89. const __m128i lut = _mm_setr_epi8( \
  90. 19, 16, 4, 4, \
  91. 4, 4, 4, 4, \
  92. 4, 4, 4, 4, \
  93. 0, 0, -71, -65 \
  94. ); \
  95. const __m128i range = _mm_setr_epi8( \
  96. '+','+', \
  97. '+','+', \
  98. '+','+', \
  99. '+','+', \
  100. '/','/', \
  101. '0','9', \
  102. 'A','Z', \
  103. 'a','z'); \
  104. if (_mm_cmpistrc(range, str, _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | _SIDD_NEGATIVE_POLARITY)) { \
  105. seen_error = true; \
  106. break; \
  107. } \
  108. __m128i indices = _mm_subs_epu8(str, _mm_set1_epi8(46)); \
  109. __m128i mask45 = CMPGT(str, 64); \
  110. __m128i mask5 = CMPGT(str, 96); \
  111. indices = _mm_andnot_si128(mask45, indices); \
  112. mask45 = _mm_add_epi8(_mm_slli_epi16(_mm_abs_epi8(mask45), 4), mask45); \
  113. indices = _mm_add_epi8(indices, mask45); \
  114. indices = _mm_add_epi8(indices, mask5); \
  115. __m128i delta = _mm_shuffle_epi8(lut, indices); \
  116. str = _mm_add_epi8(str, delta); \
  117. str = dec_reshuffle(str); \
  118. _mm_storeu_si128((__m128i *)o, str); \
  119. c += 16; \
  120. o += 12; \
  121. outl += 12; \
  122. inlen -= 16; \
  123. }
  124. int
  125. base64_decode_sse42 (const char *in, size_t inlen,
  126. unsigned char *out, size_t *outlen) __attribute__((__target__("sse4.2")));
  127. int
  128. base64_decode_sse42 (const char *in, size_t inlen,
  129. unsigned char *out, size_t *outlen)
  130. {
  131. ssize_t ret = 0;
  132. const uint8_t *c = (const uint8_t *)in;
  133. uint8_t *o = (uint8_t *)out;
  134. uint8_t q, carry;
  135. size_t outl = 0;
  136. size_t leftover = 0;
  137. bool seen_error = false;
  138. repeat:
  139. switch (leftover) {
  140. for (;;) {
  141. case 0:
  142. if (G_LIKELY (!seen_error)) {
  143. INNER_LOOP_SSE42
  144. }
  145. if (inlen-- == 0) {
  146. ret = 1;
  147. break;
  148. }
  149. if ((q = base64_table_dec[*c++]) >= 254) {
  150. ret = 0;
  151. break;
  152. }
  153. carry = q << 2;
  154. leftover++;
  155. case 1:
  156. if (inlen-- == 0) {
  157. ret = 1;
  158. break;
  159. }
  160. if ((q = base64_table_dec[*c++]) >= 254) {
  161. ret = 0;
  162. break;
  163. }
  164. *o++ = carry | (q >> 4);
  165. carry = q << 4;
  166. leftover++;
  167. outl++;
  168. case 2:
  169. if (inlen-- == 0) {
  170. ret = 1;
  171. break;
  172. }
  173. if ((q = base64_table_dec[*c++]) >= 254) {
  174. leftover++;
  175. if (q == 254) {
  176. if (inlen-- != 0) {
  177. leftover = 0;
  178. q = base64_table_dec[*c++];
  179. ret = ((q == 254) && (inlen == 0)) ? 1 : 0;
  180. break;
  181. }
  182. else {
  183. ret = 1;
  184. break;
  185. }
  186. }
  187. else {
  188. leftover --;
  189. }
  190. /* If we get here, there was an error: */
  191. break;
  192. }
  193. *o++ = carry | (q >> 2);
  194. carry = q << 6;
  195. leftover++;
  196. outl++;
  197. case 3:
  198. if (inlen-- == 0) {
  199. ret = 1;
  200. break;
  201. }
  202. if ((q = base64_table_dec[*c++]) >= 254) {
  203. /*
  204. * When q == 254, the input char is '='. Return 1 and EOF.
  205. * When q == 255, the input char is invalid. Return 0 and EOF.
  206. */
  207. if (q == 254 && inlen == 0) {
  208. ret = 1;
  209. leftover = 0;
  210. }
  211. else {
  212. ret = 0;
  213. }
  214. break;
  215. }
  216. *o++ = carry | q;
  217. carry = 0;
  218. leftover = 0;
  219. outl++;
  220. }
  221. }
  222. if (!ret && inlen > 0) {
  223. /* Skip to the next valid character in input */
  224. while (inlen > 0 && base64_table_dec[*c] >= 254) {
  225. c ++;
  226. inlen --;
  227. }
  228. if (inlen > 0) {
  229. seen_error = false;
  230. goto repeat;
  231. }
  232. }
  233. *outlen = outl;
  234. return ret;
  235. }
  236. #if defined(__GNUC__) && !defined(__clang__)
  237. #pragma GCC pop_options
  238. #endif
  239. #endif