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 }