SHA-512: Add AVX and AVX2 implementations for x86-64
[libgcrypt.git] / cipher / cast5-arm.S
1 /* cast5-arm.S  -  ARM assembly implementation of CAST5 cipher
2  *
3  * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
4  *
5  * This file is part of Libgcrypt.
6  *
7  * Libgcrypt is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * Libgcrypt is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #if defined(__ARMEL__)
24 #ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS
25
26 .text
27
28 .syntax unified
29 .arm
30
31 .extern _gcry_cast5_s1to4;
32
33 /* structure of crypto context */
34 #define Km 0
35 #define Kr (Km + (16 * 4))
36 #define Kr_arm_enc (Kr + (16))
37 #define Kr_arm_dec (Kr_arm_enc + (16))
38
39 /* register macros */
40 #define CTX %r0
41 #define Rs1 %r7
42 #define Rs2 %r8
43 #define Rs3 %r9
44 #define Rs4 %r10
45 #define RMASK %r11
46 #define RKM %r1
47 #define RKR %r2
48
49 #define RL0 %r3
50 #define RR0 %r4
51
52 #define RL1 %r9
53 #define RR1 %r10
54
55 #define RT0 %lr
56 #define RT1 %ip
57 #define RT2 %r5
58 #define RT3 %r6
59
60 /* helper macros */
61 #define ldr_unaligned_le(rout, rsrc, offs, rtmp) \
62         ldrb rout, [rsrc, #((offs) + 0)]; \
63         ldrb rtmp, [rsrc, #((offs) + 1)]; \
64         orr rout, rout, rtmp, lsl #8; \
65         ldrb rtmp, [rsrc, #((offs) + 2)]; \
66         orr rout, rout, rtmp, lsl #16; \
67         ldrb rtmp, [rsrc, #((offs) + 3)]; \
68         orr rout, rout, rtmp, lsl #24;
69
70 #define str_unaligned_le(rin, rdst, offs, rtmp0, rtmp1) \
71         mov rtmp0, rin, lsr #8; \
72         strb rin, [rdst, #((offs) + 0)]; \
73         mov rtmp1, rin, lsr #16; \
74         strb rtmp0, [rdst, #((offs) + 1)]; \
75         mov rtmp0, rin, lsr #24; \
76         strb rtmp1, [rdst, #((offs) + 2)]; \
77         strb rtmp0, [rdst, #((offs) + 3)];
78
79 #define ldr_unaligned_be(rout, rsrc, offs, rtmp) \
80         ldrb rout, [rsrc, #((offs) + 3)]; \
81         ldrb rtmp, [rsrc, #((offs) + 2)]; \
82         orr rout, rout, rtmp, lsl #8; \
83         ldrb rtmp, [rsrc, #((offs) + 1)]; \
84         orr rout, rout, rtmp, lsl #16; \
85         ldrb rtmp, [rsrc, #((offs) + 0)]; \
86         orr rout, rout, rtmp, lsl #24;
87
88 #define str_unaligned_be(rin, rdst, offs, rtmp0, rtmp1) \
89         mov rtmp0, rin, lsr #8; \
90         strb rin, [rdst, #((offs) + 3)]; \
91         mov rtmp1, rin, lsr #16; \
92         strb rtmp0, [rdst, #((offs) + 2)]; \
93         mov rtmp0, rin, lsr #24; \
94         strb rtmp1, [rdst, #((offs) + 1)]; \
95         strb rtmp0, [rdst, #((offs) + 0)];
96
97 #ifdef __ARMEL__
98         #define ldr_unaligned_host ldr_unaligned_le
99         #define str_unaligned_host str_unaligned_le
100
101         /* bswap on little-endian */
102 #ifdef HAVE_ARM_ARCH_V6
103         #define host_to_be(reg, rtmp) \
104                 rev reg, reg;
105         #define be_to_host(reg, rtmp) \
106                 rev reg, reg;
107 #else
108         #define host_to_be(reg, rtmp) \
109                 eor     rtmp, reg, reg, ror #16; \
110                 mov     rtmp, rtmp, lsr #8; \
111                 bic     rtmp, rtmp, #65280; \
112                 eor     reg, rtmp, reg, ror #8;
113         #define be_to_host(reg, rtmp) \
114                 eor     rtmp, reg, reg, ror #16; \
115                 mov     rtmp, rtmp, lsr #8; \
116                 bic     rtmp, rtmp, #65280; \
117                 eor     reg, rtmp, reg, ror #8;
118 #endif
119 #else
120         #define ldr_unaligned_host ldr_unaligned_be
121         #define str_unaligned_host str_unaligned_be
122
123         /* nop on big-endian */
124         #define host_to_be(reg, rtmp) /*_*/
125         #define be_to_host(reg, rtmp) /*_*/
126 #endif
127
128 #define host_to_host(x, y) /*_*/
129
130 /**********************************************************************
131   1-way cast5
132  **********************************************************************/
133
134 #define dummy(n) /*_*/
135
136 #define load_kr(n) \
137         ldr RKR, [CTX, #(Kr_arm_enc + (n))]; /* Kr[n] */
138
139 #define load_dec_kr(n) \
140         ldr RKR, [CTX, #(Kr_arm_dec + (n) - 3)]; /* Kr[n] */
141
142 #define load_km(n) \
143         ldr RKM, [CTX, #(Km + (n) * 4)]; /* Km[n] */
144
145 #define shift_kr(dummy) \
146         mov RKR, RKR, lsr #8;
147
148 #define F(n, rl, rr, op1, op2, op3, op4, dec, loadkm, shiftkr, loadkr) \
149         op1 RKM, rr; \
150         mov RKM, RKM, ror RKR; \
151         \
152         and RT0, RMASK, RKM, ror #(24); \
153         and RT1, RMASK, RKM, lsr #(16); \
154         and RT2, RMASK, RKM, lsr #(8); \
155         ldr RT0, [Rs1, RT0]; \
156         and RT3, RMASK, RKM; \
157         ldr RT1, [Rs2, RT1]; \
158         shiftkr(RKR); \
159         \
160         ldr RT2, [Rs3, RT2]; \
161         \
162         op2 RT0, RT1; \
163         ldr RT3, [Rs4, RT3]; \
164         op3 RT0, RT2; \
165         loadkm((n) + (1 - ((dec) * 2))); \
166         op4 RT0, RT3; \
167         loadkr((n) + (1 - ((dec) * 2))); \
168         eor rl, RT0;
169
170 #define F1(n, rl, rr, dec, loadkm, shiftkr, loadkr) \
171         F(n, rl, rr, add, eor, sub, add, dec, loadkm, shiftkr, loadkr)
172 #define F2(n, rl, rr, dec, loadkm, shiftkr, loadkr) \
173         F(n, rl, rr, eor, sub, add, eor, dec, loadkm, shiftkr, loadkr)
174 #define F3(n, rl, rr, dec, loadkm, shiftkr, loadkr) \
175         F(n, rl, rr, sub, add, eor, sub, dec, loadkm, shiftkr, loadkr)
176
177 #define enc_round(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \
178         Fx(n, rl, rr, 0, loadkm, shiftkr, loadkr)
179
180 #define dec_round(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \
181         Fx(n, rl, rr, 1, loadkm, shiftkr, loadkr)
182
183 #define read_block_aligned(rin, offs, l0, r0, convert, rtmp) \
184         ldr l0, [rin, #((offs) + 0)]; \
185         ldr r0, [rin, #((offs) + 4)]; \
186         convert(l0, rtmp); \
187         convert(r0, rtmp);
188
189 #define write_block_aligned(rout, offs, l0, r0, convert, rtmp) \
190         convert(l0, rtmp); \
191         convert(r0, rtmp); \
192         str l0, [rout, #((offs) + 0)]; \
193         str r0, [rout, #((offs) + 4)];
194
195 #ifdef __ARM_FEATURE_UNALIGNED
196         /* unaligned word reads allowed */
197         #define read_block(rin, offs, l0, r0, rtmp0) \
198                 read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0)
199
200         #define write_block(rout, offs, r0, l0, rtmp0, rtmp1) \
201                 write_block_aligned(rout, offs, r0, l0, be_to_host, rtmp0)
202
203         #define read_block_host(rin, offs, l0, r0, rtmp0) \
204                 read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0)
205
206         #define write_block_host(rout, offs, r0, l0, rtmp0, rtmp1) \
207                 write_block_aligned(rout, offs, r0, l0, host_to_host, rtmp0)
208 #else
209         /* need to handle unaligned reads by byte reads */
210         #define read_block(rin, offs, l0, r0, rtmp0) \
211                 tst rin, #3; \
212                 beq 1f; \
213                         ldr_unaligned_be(l0, rin, (offs) + 0, rtmp0); \
214                         ldr_unaligned_be(r0, rin, (offs) + 4, rtmp0); \
215                         b 2f; \
216                 1:;\
217                         read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0); \
218                 2:;
219
220         #define write_block(rout, offs, l0, r0, rtmp0, rtmp1) \
221                 tst rout, #3; \
222                 beq 1f; \
223                         str_unaligned_be(l0, rout, (offs) + 0, rtmp0, rtmp1); \
224                         str_unaligned_be(r0, rout, (offs) + 4, rtmp0, rtmp1); \
225                         b 2f; \
226                 1:;\
227                         write_block_aligned(rout, offs, l0, r0, be_to_host, rtmp0); \
228                 2:;
229
230         #define read_block_host(rin, offs, l0, r0, rtmp0) \
231                 tst rin, #3; \
232                 beq 1f; \
233                         ldr_unaligned_host(l0, rin, (offs) + 0, rtmp0); \
234                         ldr_unaligned_host(r0, rin, (offs) + 4, rtmp0); \
235                         b 2f; \
236                 1:;\
237                         read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0); \
238                 2:;
239
240         #define write_block_host(rout, offs, l0, r0, rtmp0, rtmp1) \
241                 tst rout, #3; \
242                 beq 1f; \
243                         str_unaligned_host(l0, rout, (offs) + 0, rtmp0, rtmp1); \
244                         str_unaligned_host(r0, rout, (offs) + 4, rtmp0, rtmp1); \
245                         b 2f; \
246                 1:;\
247                         write_block_aligned(rout, offs, l0, r0, host_to_host, rtmp0); \
248                 2:;
249 #endif
250
251 .align 3
252 .globl _gcry_cast5_arm_encrypt_block
253 .type  _gcry_cast5_arm_encrypt_block,%function;
254
255 _gcry_cast5_arm_encrypt_block:
256         /* input:
257          *      %r0: CTX
258          *      %r1: dst
259          *      %r2: src
260          */
261         push {%r1, %r4-%r11, %ip, %lr};
262
263         ldr Rs1, =_gcry_cast5_s1to4;
264         mov RMASK, #(0xff << 2);
265         add Rs2, Rs1, #(0x100*4);
266         add Rs3, Rs1, #(0x100*4*2);
267         add Rs4, Rs1, #(0x100*4*3);
268
269         read_block(%r2, 0, RL0, RR0, RT0);
270
271         load_km(0);
272         load_kr(0);
273         enc_round(0, F1, RL0, RR0, load_km, shift_kr, dummy);
274         enc_round(1, F2, RR0, RL0, load_km, shift_kr, dummy);
275         enc_round(2, F3, RL0, RR0, load_km, shift_kr, dummy);
276         enc_round(3, F1, RR0, RL0, load_km, dummy, load_kr);
277         enc_round(4, F2, RL0, RR0, load_km, shift_kr, dummy);
278         enc_round(5, F3, RR0, RL0, load_km, shift_kr, dummy);
279         enc_round(6, F1, RL0, RR0, load_km, shift_kr, dummy);
280         enc_round(7, F2, RR0, RL0, load_km, dummy, load_kr);
281         enc_round(8, F3, RL0, RR0, load_km, shift_kr, dummy);
282         enc_round(9, F1, RR0, RL0, load_km, shift_kr, dummy);
283         enc_round(10, F2, RL0, RR0, load_km, shift_kr, dummy);
284         enc_round(11, F3, RR0, RL0, load_km, dummy, load_kr);
285         enc_round(12, F1, RL0, RR0, load_km, shift_kr, dummy);
286         enc_round(13, F2, RR0, RL0, load_km, shift_kr, dummy);
287         enc_round(14, F3, RL0, RR0, load_km, shift_kr, dummy);
288         enc_round(15, F1, RR0, RL0, dummy, dummy, dummy);
289
290         ldr %r1, [%sp], #4;
291         write_block(%r1, 0, RR0, RL0, RT0, RT1);
292
293         pop {%r4-%r11, %ip, %pc};
294 .ltorg
295 .size _gcry_cast5_arm_encrypt_block,.-_gcry_cast5_arm_encrypt_block;
296
297 .align 3
298 .globl _gcry_cast5_arm_decrypt_block
299 .type  _gcry_cast5_arm_decrypt_block,%function;
300
301 _gcry_cast5_arm_decrypt_block:
302         /* input:
303          *      %r0: CTX
304          *      %r1: dst
305          *      %r2: src
306          */
307         push {%r1, %r4-%r11, %ip, %lr};
308
309         ldr Rs1, =_gcry_cast5_s1to4;
310         mov RMASK, #(0xff << 2);
311         add Rs2, Rs1, #(0x100 * 4);
312         add Rs3, Rs1, #(0x100 * 4 * 2);
313         add Rs4, Rs1, #(0x100 * 4 * 3);
314
315         read_block(%r2, 0, RL0, RR0, RT0);
316
317         load_km(15);
318         load_dec_kr(15);
319         dec_round(15, F1, RL0, RR0, load_km, shift_kr, dummy);
320         dec_round(14, F3, RR0, RL0, load_km, shift_kr, dummy);
321         dec_round(13, F2, RL0, RR0, load_km, shift_kr, dummy);
322         dec_round(12, F1, RR0, RL0, load_km, dummy, load_dec_kr);
323         dec_round(11, F3, RL0, RR0, load_km, shift_kr, dummy);
324         dec_round(10, F2, RR0, RL0, load_km, shift_kr, dummy);
325         dec_round(9, F1, RL0, RR0, load_km, shift_kr, dummy);
326         dec_round(8, F3, RR0, RL0, load_km, dummy, load_dec_kr);
327         dec_round(7, F2, RL0, RR0, load_km, shift_kr, dummy);
328         dec_round(6, F1, RR0, RL0, load_km, shift_kr, dummy);
329         dec_round(5, F3, RL0, RR0, load_km, shift_kr, dummy);
330         dec_round(4, F2, RR0, RL0, load_km, dummy, load_dec_kr);
331         dec_round(3, F1, RL0, RR0, load_km, shift_kr, dummy);
332         dec_round(2, F3, RR0, RL0, load_km, shift_kr, dummy);
333         dec_round(1, F2, RL0, RR0, load_km, shift_kr, dummy);
334         dec_round(0, F1, RR0, RL0, dummy, dummy, dummy);
335
336         ldr %r1, [%sp], #4;
337         write_block(%r1, 0, RR0, RL0, RT0, RT1);
338
339         pop {%r4-%r11, %ip, %pc};
340 .ltorg
341 .size _gcry_cast5_arm_decrypt_block,.-_gcry_cast5_arm_decrypt_block;
342
343 /**********************************************************************
344   2-way cast5
345  **********************************************************************/
346
347 #define F_2w(n, rl0, rr0, rl1, rr1, op1, op2, op3, op4, dec, loadkm, shiftkr, \
348              loadkr) \
349         op1 RT3, RKM, rr0; \
350         op1 RKM, RKM, rr1; \
351         mov RT3, RT3, ror RKR; \
352         mov RKM, RKM, ror RKR; \
353         \
354         and RT0, RMASK, RT3, ror #(24); \
355         and RT1, RMASK, RT3, lsr #(16); \
356         and RT2, RMASK, RT3, lsr #(8); \
357         and RT3, RMASK, RT3; \
358         \
359         ldr RT0, [Rs1, RT0]; \
360         add RT2, #(0x100 * 4); \
361         ldr RT1, [Rs2, RT1]; \
362         add RT3, #(0x100 * 4 * 2); \
363         \
364         ldr RT2, [Rs2, RT2]; \
365         \
366         op2 RT0, RT1; \
367         ldr RT3, [Rs2, RT3]; \
368         and RT1, RMASK, RKM, ror #(24); \
369         op3 RT0, RT2; \
370         and RT2, RMASK, RKM, lsr #(16); \
371         op4 RT0, RT3; \
372         and RT3, RMASK, RKM, lsr #(8); \
373         eor rl0, RT0; \
374         add RT3, #(0x100 * 4); \
375         ldr RT1, [Rs1, RT1]; \
376         and RT0, RMASK, RKM; \
377         ldr RT2, [Rs2, RT2]; \
378         add RT0, #(0x100 * 4 * 2); \
379         \
380         ldr RT3, [Rs2, RT3]; \
381         \
382         op2 RT1, RT2; \
383         ldr RT0, [Rs2, RT0]; \
384         op3 RT1, RT3; \
385         loadkm((n) + (1 - ((dec) * 2))); \
386         op4 RT1, RT0; \
387         loadkr((n) + (1 - ((dec) * 2))); \
388         shiftkr(RKR); \
389         eor rl1, RT1;
390
391 #define F1_2w(n, rl0, rr0, rl1, rr1, dec, loadkm, shiftkr, loadkr) \
392         F_2w(n, rl0, rr0, rl1, rr1, add, eor, sub, add, dec, \
393              loadkm, shiftkr, loadkr)
394 #define F2_2w(n, rl0, rr0, rl1, rr1, dec, loadkm, shiftkr, loadkr) \
395         F_2w(n, rl0, rr0, rl1, rr1, eor, sub, add, eor, dec, \
396              loadkm, shiftkr, loadkr)
397 #define F3_2w(n, rl0, rr0, rl1, rr1, dec, loadkm, shiftkr, loadkr) \
398         F_2w(n, rl0, rr0, rl1, rr1, sub, add, eor, sub, dec, \
399              loadkm, shiftkr, loadkr)
400
401 #define enc_round2(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \
402         Fx##_2w(n, rl##0, rr##0, rl##1, rr##1, 0, loadkm, shiftkr, loadkr)
403
404 #define dec_round2(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \
405         Fx##_2w(n, rl##0, rr##0, rl##1, rr##1, 1, loadkm, shiftkr, loadkr)
406
407 #define read_block2_aligned(rin, l0, r0, l1, r1, convert, rtmp) \
408         ldr l0, [rin, #(0)]; \
409         ldr r0, [rin, #(4)]; \
410         convert(l0, rtmp); \
411         ldr l1, [rin, #(8)]; \
412         convert(r0, rtmp); \
413         ldr r1, [rin, #(12)]; \
414         convert(l1, rtmp); \
415         convert(r1, rtmp);
416
417 #define write_block2_aligned(rout, l0, r0, l1, r1, convert, rtmp) \
418         convert(l0, rtmp); \
419         convert(r0, rtmp); \
420         convert(l1, rtmp); \
421         str l0, [rout, #(0)]; \
422         convert(r1, rtmp); \
423         str r0, [rout, #(4)]; \
424         str l1, [rout, #(8)]; \
425         str r1, [rout, #(12)];
426
427 #ifdef __ARM_FEATURE_UNALIGNED
428         /* unaligned word reads allowed */
429         #define read_block2(rin, l0, r0, l1, r1, rtmp0) \
430                 read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0)
431
432         #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
433                 write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0)
434
435         #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \
436                 read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0)
437
438         #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
439                 write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0)
440 #else
441         /* need to handle unaligned reads by byte reads */
442         #define read_block2(rin, l0, r0, l1, r1, rtmp0) \
443                 tst rin, #3; \
444                 beq 1f; \
445                         ldr_unaligned_be(l0, rin, 0, rtmp0); \
446                         ldr_unaligned_be(r0, rin, 4, rtmp0); \
447                         ldr_unaligned_be(l1, rin, 8, rtmp0); \
448                         ldr_unaligned_be(r1, rin, 12, rtmp0); \
449                         b 2f; \
450                 1:;\
451                         read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0); \
452                 2:;
453
454         #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
455                 tst rout, #3; \
456                 beq 1f; \
457                         str_unaligned_be(l0, rout, 0, rtmp0, rtmp1); \
458                         str_unaligned_be(r0, rout, 4, rtmp0, rtmp1); \
459                         str_unaligned_be(l1, rout, 8, rtmp0, rtmp1); \
460                         str_unaligned_be(r1, rout, 12, rtmp0, rtmp1); \
461                         b 2f; \
462                 1:;\
463                         write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0); \
464                 2:;
465
466         #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \
467                 tst rin, #3; \
468                 beq 1f; \
469                         ldr_unaligned_host(l0, rin, 0, rtmp0); \
470                         ldr_unaligned_host(r0, rin, 4, rtmp0); \
471                         ldr_unaligned_host(l1, rin, 8, rtmp0); \
472                         ldr_unaligned_host(r1, rin, 12, rtmp0); \
473                         b 2f; \
474                 1:;\
475                         read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0); \
476                 2:;
477
478         #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
479                 tst rout, #3; \
480                 beq 1f; \
481                         str_unaligned_host(l0, rout, 0, rtmp0, rtmp1); \
482                         str_unaligned_host(r0, rout, 4, rtmp0, rtmp1); \
483                         str_unaligned_host(l1, rout, 8, rtmp0, rtmp1); \
484                         str_unaligned_host(r1, rout, 12, rtmp0, rtmp1); \
485                         b 2f; \
486                 1:;\
487                         write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0); \
488                 2:;
489 #endif
490
491 .align 3
492 .type  _gcry_cast5_arm_enc_blk2,%function;
493
494 _gcry_cast5_arm_enc_blk2:
495         /* input:
496          *      preloaded: CTX
497          *      [RL0, RR0], [RL1, RR1]: src
498          * output:
499          *      [RR0, RL0], [RR1, RL1]: dst
500          */
501         push {%lr};
502
503         ldr Rs1, =_gcry_cast5_s1to4;
504         mov RMASK, #(0xff << 2);
505         add Rs2, Rs1, #(0x100 * 4);
506
507         load_km(0);
508         load_kr(0);
509         enc_round2(0, F1, RL, RR, load_km, shift_kr, dummy);
510         enc_round2(1, F2, RR, RL, load_km, shift_kr, dummy);
511         enc_round2(2, F3, RL, RR, load_km, shift_kr, dummy);
512         enc_round2(3, F1, RR, RL, load_km, dummy, load_kr);
513         enc_round2(4, F2, RL, RR, load_km, shift_kr, dummy);
514         enc_round2(5, F3, RR, RL, load_km, shift_kr, dummy);
515         enc_round2(6, F1, RL, RR, load_km, shift_kr, dummy);
516         enc_round2(7, F2, RR, RL, load_km, dummy, load_kr);
517         enc_round2(8, F3, RL, RR, load_km, shift_kr, dummy);
518         enc_round2(9, F1, RR, RL, load_km, shift_kr, dummy);
519         enc_round2(10, F2, RL, RR, load_km, shift_kr, dummy);
520         enc_round2(11, F3, RR, RL, load_km, dummy, load_kr);
521         enc_round2(12, F1, RL, RR, load_km, shift_kr, dummy);
522         enc_round2(13, F2, RR, RL, load_km, shift_kr, dummy);
523         enc_round2(14, F3, RL, RR, load_km, shift_kr, dummy);
524         enc_round2(15, F1, RR, RL, dummy, dummy, dummy);
525
526         host_to_be(RR0, RT0);
527         host_to_be(RL0, RT0);
528         host_to_be(RR1, RT0);
529         host_to_be(RL1, RT0);
530
531         pop {%pc};
532 .ltorg
533 .size _gcry_cast5_arm_enc_blk2,.-_gcry_cast5_arm_enc_blk2;
534
535 .align 3
536 .globl _gcry_cast5_arm_cfb_dec;
537 .type  _gcry_cast5_arm_cfb_dec,%function;
538
539 _gcry_cast5_arm_cfb_dec:
540         /* input:
541          *      %r0: CTX
542          *      %r1: dst (2 blocks)
543          *      %r2: src (2 blocks)
544          *      %r3: iv (64bit)
545          */
546         push {%r1, %r2, %r4-%r11, %ip, %lr};
547
548         mov %lr, %r3;
549
550         /* Load input (iv/%r3 is aligned, src/%r2 might not be) */
551         ldm %r3, {RL0, RR0};
552         host_to_be(RL0, RT1);
553         host_to_be(RR0, RT1);
554         read_block(%r2, 0, RL1, RR1, %ip);
555
556         /* Update IV, load src[1] and save to iv[0] */
557         read_block_host(%r2, 8, %r5, %r6, %r7);
558         stm %lr, {%r5, %r6};
559
560         bl _gcry_cast5_arm_enc_blk2;
561         /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */
562
563         /* %r0: dst, %r1: %src */
564         pop {%r0, %r1};
565
566         /* dst = src ^ result */
567         read_block2_host(%r1, %r5, %r6, %r7, %r8, %lr);
568         eor %r5, %r4;
569         eor %r6, %r3;
570         eor %r7, %r10;
571         eor %r8, %r9;
572         write_block2_host(%r0, %r5, %r6, %r7, %r8, %r1, %r2);
573
574         pop {%r4-%r11, %ip, %pc};
575 .ltorg
576 .size _gcry_cast5_arm_cfb_dec,.-_gcry_cast5_arm_cfb_dec;
577
578 .align 3
579 .globl _gcry_cast5_arm_ctr_enc;
580 .type  _gcry_cast5_arm_ctr_enc,%function;
581
582 _gcry_cast5_arm_ctr_enc:
583         /* input:
584          *      %r0: CTX
585          *      %r1: dst (2 blocks)
586          *      %r2: src (2 blocks)
587          *      %r3: iv (64bit, big-endian)
588          */
589         push {%r1, %r2, %r4-%r11, %ip, %lr};
590
591         mov %lr, %r3;
592
593         /* Load IV (big => host endian) */
594         read_block_aligned(%lr, 0, RL0, RR0, be_to_host, RT1);
595
596         /* Construct IVs */
597         adds RR1, RR0, #1; /* +1 */
598         adc RL1, RL0, #0;
599         adds %r6, RR1, #1; /* +2 */
600         adc %r5, RL1, #0;
601
602         /* Store new IV (host => big-endian) */
603         write_block_aligned(%lr, 0, %r5, %r6, host_to_be, RT1);
604
605         bl _gcry_cast5_arm_enc_blk2;
606         /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */
607
608         /* %r0: dst, %r1: %src */
609         pop {%r0, %r1};
610
611         /* XOR key-stream with plaintext */
612         read_block2_host(%r1, %r5, %r6, %r7, %r8, %lr);
613         eor %r5, %r4;
614         eor %r6, %r3;
615         eor %r7, %r10;
616         eor %r8, %r9;
617         write_block2_host(%r0, %r5, %r6, %r7, %r8, %r1, %r2);
618
619         pop {%r4-%r11, %ip, %pc};
620 .ltorg
621 .size _gcry_cast5_arm_ctr_enc,.-_gcry_cast5_arm_ctr_enc;
622
623 .align 3
624 .type  _gcry_cast5_arm_dec_blk2,%function;
625
626 _gcry_cast5_arm_dec_blk2:
627         /* input:
628          *      preloaded: CTX
629          *      [RL0, RR0], [RL1, RR1]: src
630          * output:
631          *      [RR0, RL0], [RR1, RL1]: dst
632          */
633
634         ldr Rs1, =_gcry_cast5_s1to4;
635         mov RMASK, #(0xff << 2);
636         add Rs2, Rs1, #(0x100 * 4);
637
638         load_km(15);
639         load_dec_kr(15);
640         dec_round2(15, F1, RL, RR, load_km, shift_kr, dummy);
641         dec_round2(14, F3, RR, RL, load_km, shift_kr, dummy);
642         dec_round2(13, F2, RL, RR, load_km, shift_kr, dummy);
643         dec_round2(12, F1, RR, RL, load_km, dummy, load_dec_kr);
644         dec_round2(11, F3, RL, RR, load_km, shift_kr, dummy);
645         dec_round2(10, F2, RR, RL, load_km, shift_kr, dummy);
646         dec_round2(9, F1, RL, RR, load_km, shift_kr, dummy);
647         dec_round2(8, F3, RR, RL, load_km, dummy, load_dec_kr);
648         dec_round2(7, F2, RL, RR, load_km, shift_kr, dummy);
649         dec_round2(6, F1, RR, RL, load_km, shift_kr, dummy);
650         dec_round2(5, F3, RL, RR, load_km, shift_kr, dummy);
651         dec_round2(4, F2, RR, RL, load_km, dummy, load_dec_kr);
652         dec_round2(3, F1, RL, RR, load_km, shift_kr, dummy);
653         dec_round2(2, F3, RR, RL, load_km, shift_kr, dummy);
654         dec_round2(1, F2, RL, RR, load_km, shift_kr, dummy);
655         dec_round2(0, F1, RR, RL, dummy, dummy, dummy);
656
657         host_to_be(RR0, RT0);
658         host_to_be(RL0, RT0);
659         host_to_be(RR1, RT0);
660         host_to_be(RL1, RT0);
661
662         b .Ldec_cbc_tail;
663 .ltorg
664 .size _gcry_cast5_arm_dec_blk2,.-_gcry_cast5_arm_dec_blk2;
665
666 .align 3
667 .globl _gcry_cast5_arm_cbc_dec;
668 .type  _gcry_cast5_arm_cbc_dec,%function;
669
670 _gcry_cast5_arm_cbc_dec:
671         /* input:
672          *      %r0: CTX
673          *      %r1: dst (2 blocks)
674          *      %r2: src (2 blocks)
675          *      %r3: iv (64bit)
676          */
677         push {%r1-%r11, %ip, %lr};
678
679         read_block2(%r2, RL0, RR0, RL1, RR1, RT0);
680
681         /* dec_blk2 is only used by cbc_dec, jump directly in/out instead
682          * of function call. */
683         b _gcry_cast5_arm_dec_blk2;
684 .Ldec_cbc_tail:
685         /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */
686
687         /* %r0: dst, %r1: %src, %r2: iv */
688         pop {%r0-%r2};
689
690         /* load IV+1 (src[0]) to %r7:%r8. Might be unaligned. */
691         read_block_host(%r1, 0, %r7, %r8, %r5);
692         /* load IV (iv[0]) to %r5:%r6. 'iv' is aligned. */
693         ldm %r2, {%r5, %r6};
694
695         /* out[1] ^= IV+1 */
696         eor %r10, %r7;
697         eor %r9, %r8;
698         /* out[0] ^= IV */
699         eor %r4, %r5;
700         eor %r3, %r6;
701
702         /* load IV+2 (src[1]) to %r7:%r8. Might be unaligned. */
703         read_block_host(%r1, 8, %r7, %r8, %r5);
704         /* store IV+2 to iv[0] (aligned). */
705         stm %r2, {%r7, %r8};
706
707         /* store result to dst[0-3]. Might be unaligned. */
708         write_block2_host(%r0, %r4, %r3, %r10, %r9, %r5, %r6);
709
710         pop {%r4-%r11, %ip, %pc};
711 .ltorg
712 .size _gcry_cast5_arm_cbc_dec,.-_gcry_cast5_arm_cbc_dec;
713
714 #endif /*HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS*/
715 #endif /*__ARM_ARCH >= 6*/