1 /** 2 * SHA intrinsics. 3 * https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#othertechs=SHA 4 * 5 * Copyright: Guillaume Piolat 2021. 6 * Johan Engelen 2021. 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 */ 9 module inteli.shaintrin; 10 11 // SHA instructions 12 // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#othertechs=SHA 13 // Note: this header will work whether you have SHA enabled or not. 14 // With LDC, use "dflags-ldc": ["-mattr=+sha"] or equivalent to actively 15 // generate SHA instructions. 16 17 public import inteli.types; 18 import inteli.internals; 19 20 static if (LDC_with_SHA) 21 { 22 private enum SHA_builtins = true; 23 } 24 else static if (GDC_with_SHA) 25 { 26 private enum SHA_builtins = true; 27 } 28 else 29 { 30 private enum SHA_builtins = false; 31 } 32 33 nothrow @nogc: 34 35 /+ 36 /// Perform an intermediate calculation for the next four SHA1 message values (unsigned 32-bit integers) using previous message values from a and b, and store the result in dst. 37 __m128i _mm_sha1nexte_epu32(__m128i a, __m128i b) @trusted 38 { 39 static if (SHA_builtins) 40 { 41 return __builtin_ia32_sha1nexte(cast(int4) a, cast(int4) b); 42 } 43 else 44 { 45 assert(0); 46 } 47 } 48 unittest 49 { 50 } 51 +/ 52 53 /+ 54 /// Perform the final calculation for the next four SHA1 message values (unsigned 32-bit integers) using the intermediate result in a and the previous message values in b, and store the result in dst. 55 __m128i _mm_sha1msg1_epu32(__m128i a, __m128i b) @trusted 56 { 57 static if (SHA_builtins) 58 { 59 return __builtin_ia32_sha1msg1(cast(int4) a, cast(int4) b); 60 } 61 else 62 { 63 assert(0); 64 } 65 } 66 unittest 67 { 68 } 69 +/ 70 71 /+ 72 /// Calculate SHA1 state variable E after four rounds of operation from the current SHA1 state variable a, add that value to the scheduled values (unsigned 32-bit integers) in b, and store the result in dst. 73 __m128i _mm_sha1msg2_epu32(__m128i a, __m128i b) @trusted 74 { 75 static if (SHA_builtins) 76 { 77 return __builtin_ia32_sha1msg2(cast(int4) a, cast(int4) b); 78 } 79 else 80 { 81 assert(0); 82 } 83 } 84 unittest 85 { 86 } 87 +/ 88 89 /+ 90 /// Perform four rounds of SHA1 operation using an initial SHA1 state (A,B,C,D) from a and some pre-computed sum of the next 4 round message values (unsigned 32-bit integers), and state variable E from b, and store the updated SHA1 state (A,B,C,D) in dst. func contains the logic functions and round constants. 91 __m128i _mm_sha1rnds4_epu32(__m128i a, __m128i b, const int func) @trusted 92 { 93 static if (SHA_builtins) 94 { 95 return __builtin_ia32_sha1rnds4(cast(int4) a, cast(int4) b, func); 96 } 97 else 98 { 99 assert(0); 100 } 101 102 } 103 +/ 104 105 /// Perform the final calculation for the next four SHA256 message values (unsigned 32-bit integers) using previous message values from `a` and `b`, and return the result. 106 __m128i _mm_sha256msg1_epu32(__m128i a, __m128i b) @trusted 107 { 108 static if (SHA_builtins) 109 { 110 return __builtin_ia32_sha256msg1(cast(int4) a, cast(int4) b); 111 } 112 else 113 { 114 static uint sigma0(uint x) nothrow @nogc @safe 115 { 116 return bitwiseRotateRight_uint(x, 7) ^ bitwiseRotateRight_uint(x, 18) ^ x >> 3; 117 } 118 119 int4 dst; 120 int4 a4 = cast(int4) a; 121 int4 b4 = cast(int4) b; 122 uint W4 = b4.array[0]; 123 uint W3 = a4.array[3]; 124 uint W2 = a4.array[2]; 125 uint W1 = a4.array[1]; 126 uint W0 = a4.array[0]; 127 dst.ptr[3] = W3 + sigma0(W4); 128 dst.ptr[2] = W2 + sigma0(W3); 129 dst.ptr[1] = W1 + sigma0(W2); 130 dst.ptr[0] = W0 + sigma0(W1); 131 return cast(__m128i) dst; 132 } 133 } 134 unittest 135 { 136 __m128i a = [15, 20, 130, 12345]; 137 __m128i b = [15, 20, 130, 12345]; 138 __m128i result = _mm_sha256msg1_epu32(a, b); 139 assert(result.array == [671416337, 69238821, 2114864873, 503574586]); 140 } 141 142 /// Perform 2 rounds of SHA256 operation using an initial SHA256 state (C,D,G,H) from `a`, an initial SHA256 state (A,B,E,F) from `b`, and a pre-computed sum of the next 2 round message values (unsigned 32-bit integers) and the corresponding round constants from k, and return the updated SHA256 state (A,B,E,F). 143 __m128i _mm_sha256msg2_epu32(__m128i a, __m128i b) @trusted 144 { 145 static if (SHA_builtins) 146 { 147 return __builtin_ia32_sha256msg2(cast(int4) a, cast(int4) b); 148 } 149 else 150 { 151 static uint sigma1(uint x) nothrow @nogc @safe 152 { 153 return bitwiseRotateRight_uint(x, 17) ^ bitwiseRotateRight_uint(x, 19) ^ x >> 10; 154 } 155 156 int4 dst; 157 int4 a4 = cast(int4) a; 158 int4 b4 = cast(int4) b; 159 uint W14 = b4.array[2]; 160 uint W15 = b4.array[3]; 161 uint W16 = a4.array[0] + sigma1(W14); 162 uint W17 = a4.array[1] + sigma1(W15); 163 uint W18 = a4.array[2] + sigma1(W16); 164 uint W19 = a4.array[3] + sigma1(W17); 165 dst.ptr[3] = W19; 166 dst.ptr[2] = W18; 167 dst.ptr[1] = W17; 168 dst.ptr[0] = W16; 169 return cast(__m128i) dst; 170 } 171 } 172 unittest 173 { 174 __m128i a = [15, 20, 130, 12345]; 175 __m128i b = [15, 20, 130, 12345]; 176 __m128i result = _mm_sha256msg2_epu32(a, b); 177 assert(result.array == [5324815, 505126944, -2012842764, -1542210977]); 178 } 179 180 /// Perform an intermediate calculation for the next four SHA256 message values (unsigned 32-bit integers) using previous message values from `a` and `b`, and return the result. 181 __m128i _mm_sha256rnds2_epu32(__m128i a, __m128i b, __m128i k) @trusted 182 { 183 static if (SHA_builtins) 184 { 185 return __builtin_ia32_sha256rnds2(cast(int4) a, cast(int4) b, cast(int4) k); 186 } 187 else 188 { 189 static uint Ch(uint x, uint y, uint z) nothrow @nogc @safe 190 { 191 return z ^ (x & (y ^ z)); 192 } 193 194 static uint Maj(uint x, uint y, uint z) nothrow @nogc @safe 195 { 196 return (x & y) | (z & (x ^ y)); 197 } 198 199 static uint sum0(uint x) nothrow @nogc @safe 200 { 201 return bitwiseRotateRight_uint(x, 2) ^ bitwiseRotateRight_uint(x, 13) ^ bitwiseRotateRight_uint(x, 22); 202 } 203 204 static uint sum1(uint x) nothrow @nogc @safe 205 { 206 return bitwiseRotateRight_uint(x, 6) ^ bitwiseRotateRight_uint(x, 11) ^ bitwiseRotateRight_uint(x, 25); 207 } 208 209 int4 dst; 210 int4 a4 = cast(int4) a; 211 int4 b4 = cast(int4) b; 212 int4 k4 = cast(int4) k; 213 214 const A0 = b4.array[3]; 215 const B0 = b4.array[2]; 216 const C0 = a4.array[3]; 217 const D0 = a4.array[2]; 218 const E0 = b4.array[1]; 219 const F0 = b4.array[0]; 220 const G0 = a4.array[1]; 221 const H0 = a4.array[0]; 222 const W_K0 = k4.array[0]; 223 const W_K1 = k4.array[1]; 224 const A1 = Ch(E0, F0, G0) + sum1(E0) + W_K0 + H0 + Maj(A0, B0, C0) + sum0(A0); 225 const B1 = A0; 226 const C1 = B0; 227 const D1 = C0; 228 const E1 = Ch(E0, F0, G0) + sum1(E0) + W_K0 + H0 + D0; 229 const F1 = E0; 230 const G1 = F0; 231 const H1 = G0; 232 const A2 = Ch(E1, F1, G1) + sum1(E1) + W_K1 + H1 + Maj(A1, B1, C1) + sum0(A1); 233 const B2 = A1; 234 const C2 = B1; 235 const D2 = C1; 236 const E2 = Ch(E1, F1, G1) + sum1(E1) + W_K1 + H1 + D1; 237 const F2 = E1; 238 const G2 = F1; 239 const H2 = G1; 240 241 dst.ptr[3] = A2; 242 dst.ptr[2] = B2; 243 dst.ptr[1] = E2; 244 dst.ptr[0] = F2; 245 246 return cast(__m128i) dst; 247 } 248 } 249 unittest 250 { 251 __m128i a = [15, 20, 130, 12345]; 252 __m128i b = [15, 20, 130, 12345]; 253 __m128i k = [15, 20, 130, 12345]; 254 __m128i result = _mm_sha256rnds2_epu32(a, b, k); 255 assert(result.array == [1384123044, -2050674062, 327754346, 956342016]); 256 } 257 258 private uint bitwiseRotateRight_uint(const uint value, const uint count) @safe 259 { 260 assert(count < 8 * uint.sizeof); 261 return cast(uint) ((value >> count) | (value << (uint.sizeof * 8 - count))); 262 }