Imported Upstream version 9.20
[platform/upstream/7zip.git] / C / AesOpt.c
1 /* AesOpt.c -- Intel's AES\r
2 2009-11-23 : Igor Pavlov : Public domain */\r
3 \r
4 #include "CpuArch.h"\r
5 \r
6 #ifdef MY_CPU_X86_OR_AMD64\r
7 #if _MSC_VER >= 1500\r
8 #define USE_INTEL_AES\r
9 #endif\r
10 #endif\r
11 \r
12 #ifdef USE_INTEL_AES\r
13 \r
14 #include <wmmintrin.h>\r
15 \r
16 void MY_FAST_CALL AesCbc_Encode_Intel(__m128i *p, __m128i *data, size_t numBlocks)\r
17 {\r
18   __m128i m = *p;\r
19   for (; numBlocks != 0; numBlocks--, data++)\r
20   {\r
21     UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;\r
22     const __m128i *w = p + 3;\r
23     m = _mm_xor_si128(m, *data);\r
24     m = _mm_xor_si128(m, p[2]);\r
25     do\r
26     {\r
27       m = _mm_aesenc_si128(m, w[0]);\r
28       m = _mm_aesenc_si128(m, w[1]);\r
29       w += 2;\r
30     }\r
31     while (--numRounds2 != 0);\r
32     m = _mm_aesenc_si128(m, w[0]);\r
33     m = _mm_aesenclast_si128(m, w[1]);\r
34     *data = m;\r
35   }\r
36   *p = m;\r
37 }\r
38 \r
39 #define NUM_WAYS 3\r
40 \r
41 #define AES_OP_W(op, n) { \\r
42     const __m128i t = w[n]; \\r
43     m0 = op(m0, t); \\r
44     m1 = op(m1, t); \\r
45     m2 = op(m2, t); \\r
46     }\r
47 \r
48 #define AES_DEC(n) AES_OP_W(_mm_aesdec_si128, n)\r
49 #define AES_DEC_LAST(n) AES_OP_W(_mm_aesdeclast_si128, n)\r
50 #define AES_ENC(n) AES_OP_W(_mm_aesenc_si128, n)\r
51 #define AES_ENC_LAST(n) AES_OP_W(_mm_aesenclast_si128, n)\r
52 \r
53 void MY_FAST_CALL AesCbc_Decode_Intel(__m128i *p, __m128i *data, size_t numBlocks)\r
54 {\r
55   __m128i iv = *p;\r
56   for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS)\r
57   {\r
58     UInt32 numRounds2 = *(const UInt32 *)(p + 1);\r
59     const __m128i *w = p + numRounds2 * 2;\r
60     __m128i m0, m1, m2;\r
61     {\r
62       const __m128i t = w[2];\r
63       m0 = _mm_xor_si128(t, data[0]);\r
64       m1 = _mm_xor_si128(t, data[1]);\r
65       m2 = _mm_xor_si128(t, data[2]);\r
66     }\r
67     numRounds2--;\r
68     do\r
69     {\r
70       AES_DEC(1)\r
71       AES_DEC(0)\r
72       w -= 2;\r
73     }\r
74     while (--numRounds2 != 0);\r
75     AES_DEC(1)\r
76     AES_DEC_LAST(0)\r
77 \r
78     {\r
79       __m128i t;\r
80       t = _mm_xor_si128(m0, iv); iv = data[0]; data[0] = t;\r
81       t = _mm_xor_si128(m1, iv); iv = data[1]; data[1] = t;\r
82       t = _mm_xor_si128(m2, iv); iv = data[2]; data[2] = t;\r
83     }\r
84   }\r
85   for (; numBlocks != 0; numBlocks--, data++)\r
86   {\r
87     UInt32 numRounds2 = *(const UInt32 *)(p + 1);\r
88     const __m128i *w = p + numRounds2 * 2;\r
89     __m128i m = _mm_xor_si128(w[2], *data);\r
90     numRounds2--;\r
91     do\r
92     {\r
93       m = _mm_aesdec_si128(m, w[1]);\r
94       m = _mm_aesdec_si128(m, w[0]);\r
95       w -= 2;\r
96     }\r
97     while (--numRounds2 != 0);\r
98     m = _mm_aesdec_si128(m, w[1]);\r
99     m = _mm_aesdeclast_si128(m, w[0]);\r
100 \r
101     m = _mm_xor_si128(m, iv);\r
102     iv = *data;\r
103     *data = m;\r
104   }\r
105   *p = iv;\r
106 }\r
107 \r
108 void MY_FAST_CALL AesCtr_Code_Intel(__m128i *p, __m128i *data, size_t numBlocks)\r
109 {\r
110   __m128i ctr = *p;\r
111   __m128i one;\r
112   one.m128i_u64[0] = 1;\r
113   one.m128i_u64[1] = 0;\r
114   for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS)\r
115   {\r
116     UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;\r
117     const __m128i *w = p;\r
118     __m128i m0, m1, m2;\r
119     {\r
120       const __m128i t = w[2];\r
121       ctr = _mm_add_epi64(ctr, one); m0 = _mm_xor_si128(ctr, t);\r
122       ctr = _mm_add_epi64(ctr, one); m1 = _mm_xor_si128(ctr, t);\r
123       ctr = _mm_add_epi64(ctr, one); m2 = _mm_xor_si128(ctr, t);\r
124     }\r
125     w += 3;\r
126     do\r
127     {\r
128       AES_ENC(0)\r
129       AES_ENC(1)\r
130       w += 2;\r
131     }\r
132     while (--numRounds2 != 0);\r
133     AES_ENC(0)\r
134     AES_ENC_LAST(1)\r
135     data[0] = _mm_xor_si128(data[0], m0);\r
136     data[1] = _mm_xor_si128(data[1], m1);\r
137     data[2] = _mm_xor_si128(data[2], m2);\r
138   }\r
139   for (; numBlocks != 0; numBlocks--, data++)\r
140   {\r
141     UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;\r
142     const __m128i *w = p;\r
143     __m128i m;\r
144     ctr = _mm_add_epi64(ctr, one);\r
145     m = _mm_xor_si128(ctr, p[2]);\r
146     w += 3;\r
147     do\r
148     {\r
149       m = _mm_aesenc_si128(m, w[0]);\r
150       m = _mm_aesenc_si128(m, w[1]);\r
151       w += 2;\r
152     }\r
153     while (--numRounds2 != 0);\r
154     m = _mm_aesenc_si128(m, w[0]);\r
155     m = _mm_aesenclast_si128(m, w[1]);\r
156     *data = _mm_xor_si128(*data, m);\r
157   }\r
158   *p = ctr;\r
159 }\r
160 \r
161 #else\r
162 \r
163 void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);\r
164 void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);\r
165 void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);\r
166 \r
167 void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *p, Byte *data, size_t numBlocks)\r
168 {\r
169   AesCbc_Encode(p, data, numBlocks);\r
170 }\r
171 \r
172 void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *p, Byte *data, size_t numBlocks)\r
173 {\r
174   AesCbc_Decode(p, data, numBlocks);\r
175 }\r
176 \r
177 void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *p, Byte *data, size_t numBlocks)\r
178 {\r
179   AesCtr_Code(p, data, numBlocks);\r
180 }\r
181 \r
182 #endif\r