Line data Source code
1 : /* $Id: echo.c 227 2010-06-16 17:28:38Z tp $ */
2 : /*
3 : * ECHO implementation.
4 : *
5 : * ==========================(LICENSE BEGIN)============================
6 : *
7 : * Copyright (c) 2007-2010 Projet RNRT SAPHIR
8 : *
9 : * Permission is hereby granted, free of charge, to any person obtaining
10 : * a copy of this software and associated documentation files (the
11 : * "Software"), to deal in the Software without restriction, including
12 : * without limitation the rights to use, copy, modify, merge, publish,
13 : * distribute, sublicense, and/or sell copies of the Software, and to
14 : * permit persons to whom the Software is furnished to do so, subject to
15 : * the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be
18 : * included in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 : * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 : * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 : * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 : * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 : *
28 : * ===========================(LICENSE END)=============================
29 : *
30 : * @author Thomas Pornin <thomas.pornin@cryptolog.com>
31 : */
32 :
33 : #include <crypto/x11/aes.h>
34 : #include <crypto/x11/dispatch.h>
35 :
36 : #include <attributes.h>
37 :
38 : #include <cstddef>
39 : #include <cstring>
40 :
41 : #include "sph_echo.h"
42 :
43 : /*
44 : * We can use a 64-bit implementation only if a 64-bit type is available.
45 : */
46 : #ifdef _MSC_VER
47 : #pragma warning (disable: 4146)
48 : #endif
49 :
50 : #define T32 SPH_T32
51 : #define C64 SPH_C64
52 :
53 : namespace sapphire {
54 : namespace soft_echo {
55 : namespace {
56 1187320 : void ALWAYS_INLINE MixColumn(sph_u64 W[16][2], int ia, int ib, int ic, int id)
57 : {
58 3561960 : for (int n = 0; n < 2; n ++) {
59 2374640 : sph_u64 a = W[ia][n];
60 2374640 : sph_u64 b = W[ib][n];
61 2374640 : sph_u64 c = W[ic][n];
62 2374640 : sph_u64 d = W[id][n];
63 2374640 : sph_u64 ab = a ^ b;
64 2374640 : sph_u64 bc = b ^ c;
65 2374640 : sph_u64 cd = c ^ d;
66 4749280 : sph_u64 abx = ((ab & C64(0x8080808080808080)) >> 7) * 27U
67 2374640 : ^ ((ab & C64(0x7F7F7F7F7F7F7F7F)) << 1);
68 4749280 : sph_u64 bcx = ((bc & C64(0x8080808080808080)) >> 7) * 27U
69 2374640 : ^ ((bc & C64(0x7F7F7F7F7F7F7F7F)) << 1);
70 4749280 : sph_u64 cdx = ((cd & C64(0x8080808080808080)) >> 7) * 27U
71 2374640 : ^ ((cd & C64(0x7F7F7F7F7F7F7F7F)) << 1);
72 2374640 : W[ia][n] = abx ^ bc ^ d;
73 2374640 : W[ib][n] = bcx ^ a ^ cd;
74 2374640 : W[ic][n] = cdx ^ ab ^ d;
75 2374640 : W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c;
76 2374640 : }
77 1187320 : }
78 :
79 296830 : void ALWAYS_INLINE ShiftRows(uint64_t W[16][2])
80 : {
81 : #define SHIFT_ROW1(a, b, c, d) do { \
82 : sph_u64 tmp; \
83 : tmp = W[a][0]; \
84 : W[a][0] = W[b][0]; \
85 : W[b][0] = W[c][0]; \
86 : W[c][0] = W[d][0]; \
87 : W[d][0] = tmp; \
88 : tmp = W[a][1]; \
89 : W[a][1] = W[b][1]; \
90 : W[b][1] = W[c][1]; \
91 : W[c][1] = W[d][1]; \
92 : W[d][1] = tmp; \
93 : } while (0)
94 :
95 : #define SHIFT_ROW2(a, b, c, d) do { \
96 : sph_u64 tmp; \
97 : tmp = W[a][0]; \
98 : W[a][0] = W[c][0]; \
99 : W[c][0] = tmp; \
100 : tmp = W[b][0]; \
101 : W[b][0] = W[d][0]; \
102 : W[d][0] = tmp; \
103 : tmp = W[a][1]; \
104 : W[a][1] = W[c][1]; \
105 : W[c][1] = tmp; \
106 : tmp = W[b][1]; \
107 : W[b][1] = W[d][1]; \
108 : W[d][1] = tmp; \
109 : } while (0)
110 :
111 : #define SHIFT_ROW3(a, b, c, d) SHIFT_ROW1(d, c, b, a)
112 :
113 296830 : SHIFT_ROW1(1, 5, 9, 13);
114 296830 : SHIFT_ROW2(2, 6, 10, 14);
115 296830 : SHIFT_ROW3(3, 7, 11, 15);
116 :
117 : #undef SHIFT_ROW1
118 : #undef SHIFT_ROW2
119 : #undef SHIFT_ROW3
120 296830 : }
121 : } // anonymous namespace
122 :
123 296830 : void FullStateRound(sph_u64 W[16][2], sph_u32& K0, sph_u32& K1, sph_u32& K2, sph_u32& K3)
124 : {
125 5046110 : for (int n = 0; n < 16; n ++) {
126 4749280 : sph_u64 Wl = W[n][0];
127 4749280 : sph_u64 Wh = W[n][1];
128 4749280 : sph_u32 X0 = (sph_u32)Wl;
129 4749280 : sph_u32 X1 = (sph_u32)(Wl >> 32);
130 4749280 : sph_u32 X2 = (sph_u32)Wh;
131 4749280 : sph_u32 X3 = (sph_u32)(Wh >> 32);
132 4749280 : sph_u32 Y0, Y1, Y2, Y3;
133 4749280 : soft_aes::Round(X0, X1, X2, X3, K0, K1, K2, K3, Y0, Y1, Y2, Y3);
134 4749280 : soft_aes::RoundKeyless(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
135 4749280 : W[n][0] = (sph_u64)X0 | ((sph_u64)X1 << 32);
136 4749280 : W[n][1] = (sph_u64)X2 | ((sph_u64)X3 << 32);
137 4749280 : if ((K0 = T32(K0 + 1)) == 0) {
138 0 : if ((K1 = T32(K1 + 1)) == 0) {
139 0 : if ((K2 = T32(K2 + 1)) == 0) {
140 0 : K3 = T32(K3 + 1);
141 0 : }
142 0 : }
143 0 : }
144 4749280 : }
145 296830 : }
146 :
147 296830 : void ShiftAndMix(uint64_t W[16][2])
148 : {
149 296830 : ShiftRows(W);
150 296830 : MixColumn(W, 0, 1, 2, 3);
151 296830 : MixColumn(W, 4, 5, 6, 7);
152 296830 : MixColumn(W, 8, 9, 10, 11);
153 296830 : MixColumn(W, 12, 13, 14, 15);
154 296830 : }
155 : } // namespace soft_echo
156 : } // namespace sapphire
157 :
158 : sapphire::dispatch::EchoRoundFn echo_round = sapphire::soft_echo::FullStateRound;
159 : sapphire::dispatch::EchoShiftMix echo_shift_mix = sapphire::soft_echo::ShiftAndMix;
160 :
161 : #define DECL_STATE_BIG \
162 : alignas(16) sph_u64 W[16][2];
163 :
164 : #define INPUT_BLOCK_BIG(sc) do { \
165 : unsigned u; \
166 : memcpy(W, sc->u.Vb, 16 * sizeof(sph_u64)); \
167 : for (u = 0; u < 8; u ++) { \
168 : W[u + 8][0] = sph_dec64le_aligned( \
169 : sc->buf + 16 * u); \
170 : W[u + 8][1] = sph_dec64le_aligned( \
171 : sc->buf + 16 * u + 8); \
172 : } \
173 : } while (0)
174 :
175 : #define BIG_ROUND do { \
176 : echo_round(W, K0, K1, K2, K3); \
177 : echo_shift_mix(W); \
178 : } while (0)
179 :
180 : #define FINAL_BIG do { \
181 : unsigned u; \
182 : sph_u64 *VV = &sc->u.Vb[0][0]; \
183 : sph_u64 *WW = &W[0][0]; \
184 : for (u = 0; u < 16; u ++) { \
185 : VV[u] ^= sph_dec64le_aligned(sc->buf + (u * 8)) \
186 : ^ WW[u] ^ WW[u + 16]; \
187 : } \
188 : } while (0)
189 :
190 : #define COMPRESS_BIG(sc) do { \
191 : sph_u32 K0 = sc->C0; \
192 : sph_u32 K1 = sc->C1; \
193 : sph_u32 K2 = sc->C2; \
194 : sph_u32 K3 = sc->C3; \
195 : unsigned u; \
196 : INPUT_BLOCK_BIG(sc); \
197 : for (u = 0; u < 10; u ++) { \
198 : BIG_ROUND; \
199 : } \
200 : FINAL_BIG; \
201 : } while (0)
202 :
203 : #define INCR_COUNTER(sc, val) do { \
204 : sc->C0 = T32(sc->C0 + (sph_u32)(val)); \
205 : if (sc->C0 < (sph_u32)(val)) { \
206 : if ((sc->C1 = T32(sc->C1 + 1)) == 0) \
207 : if ((sc->C2 = T32(sc->C2 + 1)) == 0) \
208 : sc->C3 = T32(sc->C3 + 1); \
209 : } \
210 : } while (0)
211 :
212 : static void
213 12479421 : echo_big_init(sph_echo_big_context *sc, unsigned out_len)
214 : {
215 12479421 : sc->u.Vb[0][0] = (sph_u64)out_len;
216 12479421 : sc->u.Vb[0][1] = 0;
217 12479421 : sc->u.Vb[1][0] = (sph_u64)out_len;
218 12479421 : sc->u.Vb[1][1] = 0;
219 12479421 : sc->u.Vb[2][0] = (sph_u64)out_len;
220 12479421 : sc->u.Vb[2][1] = 0;
221 12479421 : sc->u.Vb[3][0] = (sph_u64)out_len;
222 12479421 : sc->u.Vb[3][1] = 0;
223 12479421 : sc->u.Vb[4][0] = (sph_u64)out_len;
224 12479421 : sc->u.Vb[4][1] = 0;
225 12479421 : sc->u.Vb[5][0] = (sph_u64)out_len;
226 12479421 : sc->u.Vb[5][1] = 0;
227 12479421 : sc->u.Vb[6][0] = (sph_u64)out_len;
228 12479421 : sc->u.Vb[6][1] = 0;
229 12479421 : sc->u.Vb[7][0] = (sph_u64)out_len;
230 12479421 : sc->u.Vb[7][1] = 0;
231 12479421 : sc->ptr = 0;
232 12479421 : sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0;
233 12479421 : }
234 :
235 : static void
236 6239865 : echo_big_compress(sph_echo_big_context *sc)
237 : {
238 6239865 : DECL_STATE_BIG
239 :
240 218391081 : COMPRESS_BIG(sc);
241 6239865 : }
242 :
243 : static void
244 6239640 : echo_big_core(sph_echo_big_context *sc,
245 : const unsigned char *data, size_t len)
246 : {
247 6239640 : unsigned char *buf;
248 6239640 : size_t ptr;
249 :
250 6239640 : buf = sc->buf;
251 6239640 : ptr = sc->ptr;
252 6239640 : if (len < (sizeof sc->buf) - ptr) {
253 6239640 : memcpy(buf + ptr, data, len);
254 6239640 : ptr += len;
255 6239640 : sc->ptr = ptr;
256 6239640 : return;
257 : }
258 :
259 0 : while (len > 0) {
260 0 : size_t clen;
261 :
262 0 : clen = (sizeof sc->buf) - ptr;
263 0 : if (clen > len)
264 0 : clen = len;
265 0 : memcpy(buf + ptr, data, clen);
266 0 : ptr += clen;
267 0 : data += clen;
268 0 : len -= clen;
269 0 : if (ptr == sizeof sc->buf) {
270 0 : INCR_COUNTER(sc, 1024);
271 0 : echo_big_compress(sc);
272 0 : ptr = 0;
273 0 : }
274 0 : }
275 0 : sc->ptr = ptr;
276 6239640 : }
277 :
278 : static void
279 6239619 : echo_big_close(sph_echo_big_context *sc, unsigned ub, unsigned n,
280 : void *dst, unsigned out_size_w32)
281 : {
282 6239619 : unsigned char *buf;
283 6239619 : size_t ptr;
284 6239619 : unsigned z;
285 6239619 : unsigned elen;
286 6239619 : union {
287 : unsigned char tmp[64];
288 : sph_u32 dummy;
289 : sph_u64 dummy2;
290 : } u;
291 6239619 : sph_u64 *VV;
292 6239619 : unsigned k;
293 :
294 6239619 : buf = sc->buf;
295 6239619 : ptr = sc->ptr;
296 6239619 : elen = ((unsigned)ptr << 3) + n;
297 6239619 : INCR_COUNTER(sc, elen);
298 6239619 : sph_enc32le_aligned(u.tmp, sc->C0);
299 6239619 : sph_enc32le_aligned(u.tmp + 4, sc->C1);
300 6239619 : sph_enc32le_aligned(u.tmp + 8, sc->C2);
301 6239619 : sph_enc32le_aligned(u.tmp + 12, sc->C3);
302 : /*
303 : * If elen is zero, then this block actually contains no message
304 : * bit, only the first padding bit.
305 : */
306 6239619 : if (elen == 0) {
307 0 : sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0;
308 0 : }
309 6239619 : z = 0x80 >> n;
310 6239619 : buf[ptr ++] = ((ub & -z) | z) & 0xFF;
311 6239619 : memset(buf + ptr, 0, (sizeof sc->buf) - ptr);
312 6239619 : if (ptr > ((sizeof sc->buf) - 18)) {
313 0 : echo_big_compress(sc);
314 0 : sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0;
315 0 : memset(buf, 0, sizeof sc->buf);
316 0 : }
317 6239619 : sph_enc16le(buf + (sizeof sc->buf) - 18, out_size_w32 << 5);
318 6239619 : memcpy(buf + (sizeof sc->buf) - 16, u.tmp, 16);
319 6239619 : echo_big_compress(sc);
320 56158531 : for (VV = &sc->u.Vb[0][0], k = 0; k < ((out_size_w32 + 1) >> 1); k ++)
321 49918912 : sph_enc64le_aligned(u.tmp + (k << 3), VV[k]);
322 6239619 : memcpy(dst, u.tmp, out_size_w32 << 2);
323 6239619 : echo_big_init(sc, out_size_w32 << 5);
324 6239619 : }
325 :
326 : /* see sph_echo.h */
327 : void
328 6239801 : sph_echo512_init(sph_echo512_context *cc)
329 : {
330 6239801 : echo_big_init(cc, 512);
331 6239801 : }
332 :
333 : /* see sph_echo.h */
334 : void
335 6239733 : sph_echo512(sph_echo512_context *cc, const void *data, size_t len)
336 : {
337 6239733 : echo_big_core(cc, static_cast<const unsigned char*>(data), len);
338 6239733 : }
339 :
340 : /* see sph_echo.h */
341 : void
342 6239566 : sph_echo512_close(sph_echo512_context *cc, void *dst)
343 : {
344 6239566 : echo_big_close(cc, 0, 0, dst, 16);
345 6239566 : }
346 :
347 : /* see sph_echo.h */
348 : void
349 0 : sph_echo512_addbits_and_close(sph_echo512_context *cc, unsigned ub, unsigned n, void *dst)
350 : {
351 0 : echo_big_close(cc, ub, n, dst, 16);
352 0 : }
|